Programmieren in C Programmierkurs Aufbau 1. Historisches und Grundlagen Entwicklung von Computern Prozessorarchitekturen Programmiersprachen Ein einfaches Programm 2. Rechnen, Bedingungen, Schleifen Operatoren if…else…then for while – do…while 3. Zeichen, Zeichenketten, Zeiger, Strukturen Strings Was ist ein Pointer? Strukturen/Unions Typen 19.08.2010 | FP 5 | Kernphysik | M. Platz | 2 4. Strukturiertes Programmieren Symbolische Konstanten, Makros, Header ObjektDateien/Bibliotheken/Linker 5. Spezialitäten Variable Argumentenliste Dynamischer Speicher Rekursion Zeiger auf Funktionen Tag 1 Historisches und Grundlagen Entwicklung der Rechner Rechenhilfen Abacus Rechenschieber … Programmierbare Maschinen Webstühle (1745) Klavier… Programmierbarer Rechner Nutzung eines Zwischenergebnisses für weitere Rechenoperationen Speicher Rechnervarianten Digital Analog 19.08.2010 | FP 5 | Kernphysik | M. Platz | 4 Zuse Z1 Baujahr: 1937 Elektro-Mechanisch (Binär) Ein-/Ausgabewerk Rechenwerk Speicherwerk Programmwerk Harvard-Architektur 19.08.2010 | FP 5 | Kernphysik | M. Platz | 5 Eniac Baujahr: 1942 Röhren (Binär) Rechnung im Dezimalsystem! Kein Befehlsspeicher: Verkabelt Später umgebaut auf von-Neumann-Architektur 19.08.2010 | FP 5 | Kernphysik | M. Platz | 6 Algebra Bool‘sche Algebra George Bool, englischer Mathematiker Mathematical Analysis of Logic (1847) Logik (Wahr/Falsch, 0/1) Dual-System Rechnen wie im Dezimalssystem And: 1101 0011 0001 1101 0011 1111 Or: 8 4 2 1 + 1101 =13 0011 =3 10000 - 1101 0011 1010 19.08.2010 | FP 5 | Kernphysik | M. Platz | 7 1101 0011 Excl.Or: 1110 1101 * 0011 0000 0000 1101 1101 + 100111 1101 ___________ Not: 0010 1101 : 0011 = 0100 0011 0011 -0000 0011 0011 + Rest 1 Grundlegender Aufbau einer CPU Aufbau eines „typischen“ Computerprozessors (Z80 von Zilog) Von-Neumann-Architektur Recheneinheit (ALU) Register Adress-Bus Instruction Daten-Bus Decoder Data Bus Interface Instruction Register Data Bus ALU Register Array Address Bus Address Logic and Buffers 19.08.2010 | FP 5 | Kernphysik | M. Platz | 8 Register Speicherstellen in der CPU Schnellerer Zugriff als auf RAM über den Daten-/Adressbus Teilweise bestimmte Funktionalität A F A‘ F‘ B C B‘ C‘ D E D‘ E‘ H L H‘ L‘ IX IY SP PC I 19.08.2010 | FP 5 | Kernphysik | M. Platz | 9 R Typisches Program CD91BD 3F C8 F20CA0 3E01 B7 C9 E5 1153A0 010500 EDB0 E1 … NEWSQR CALL SGN CCF RET Z JP P,GOON LD A,1 OR A RET GOON PUSH HL LD DE, STORE1 LD BC, 5 LDIR POP HL -> Hochsprache wünschenswert 19.08.2010 | FP 5 | Kernphysik | M. Platz | 10 Schnelle Funktion zum ziehen der Quadratwurzel, Brückmann, Englisch, Gerits, Steigers, „CPC Intern“ Gängige Sprachen Fortran (1954/1957, IBM) BASIC (Beginner‘s All-Pupose Symbolic Instruction Code; 1964) Pascal (1972, ETH Zürich, Lehrsprache) C (Anfang 70er, Bell Labs, Unix) C++ (Anfang 80er, AT&T) Java (Anfang 90er, SUN) 19.08.2010 | FP 5 | Kernphysik | M. Platz | 11 Übersetzen einer Hochsprache Interpreter Schrittweise Syntax-Überprüfung, Übersetzung und Ausführung des Programms (Scripte) Compreter Vollständige Syntax-Überprüfung und teilweise Übersetzung während der Ausgabe, schrittweise endgültige Übersetzung während der Ausführung, oder Schrittweise Syntax-Überprüfung und Übersetzung während der Ausführung, wenn das Programm nicht mehr geändert wird, liegt es in Übersetzter Form vor Compiler Syntax-Überprüfung und Übersetzung vor der Ausführung 19.08.2010 | FP 5 | Kernphysik | M. Platz | 12 Konventionen (Namen) Namen (Variable) Folge von Buchstaben und Ziffern Erstes Zeichen Buchstabe (_ zählt als Buchstabe) Beliebig lang Die ersten 6 Zeichen werden unterschieden Anmerkung: Implementierungen dürfen auch mehr Zeichen als relevant betrachten Interne Name sind umfassender Wenigstens 31 Zeichen werden unterschieden Case-Sensitiv 19.08.2010 | FP 5 | Kernphysik | M. Platz | 13 Konventionen (Schluesselworte) Reservierte Worte (Schlüsselworte) Anweisungen, Typen, Speicherklassen, Attribute Sehr eingeschränkter Befehlssatz -> "Maschinennah" auto break case char const continue default do double else enum extern float for goto if int long register return short signed sizeof static struct switch typedef union unsigned void volatile while 19.08.2010 | FP 5 | Kernphysik | M. Platz | 14 Konventionen (Konstanten) Konstanten Ganzzahlige Konstanten Zifferfolge (zunächst Dezimal) Präfix 0x: Hexadezimal Æ 0xAF, 0Xaf Präfix 0 (Null): Oktal Æ 072, 023 Suffix u: unsigned Æ 1234u Suffix l: long Æ 12l Zeichenkonstanten Werden in einfachen Anführungszeichen (') angegeben Æ ('a') Liefert den numerischen Wert des Zeichens im Zeichensatz der jeweiligen Maschine, auf der das Programm ausgeführt wird Möglich sind Definitionen von "wide character constants" (Präfix L) Fliesskomma Konstanten 1000.50 ; 1.0/100.0 ; 10E20 Suffix f: float Suffix l: long double Aufzählungen Ganzzahlige Konstanten (s. enum) 19.08.2010 | FP 5 | Kernphysik | M. Platz | 15 Konventionen (Strings) Konstante Zeichenketten Strings; Zeichenketten in Anführungszeichen ("…") angegeben Statischer Vektor Änderungsversuche undefiniert NUL ('\0') Terminiert Präfix L: wide character string 19.08.2010 | FP 5 | Kernphysik | M. Platz | 16 Konventionen (Operatoren) Operatoren Rechenoperationen, Zuweisung Vergleiche Bitmanipulation Adressoperatoren Sonstiges + - * ++ / -- % == && || ! < <= > >= != | << >> ~ & ^ & * ?: , = *= += -= /= %= <<= >>= &= 19.08.2010 | FP 5 | Kernphysik | M. Platz | 17 ~= |= Syntax #Präprozessoranweisung Typ Name; Typ Name=…; Typ Name (Typ Name …) { Typ Name=…; Typ Name, Name; … # Präprozessoranweisung Anweisung; # Präprozessoranweisung Anweisung; } 19.08.2010 | FP 5 | Kernphysik | M. Platz | 18 Präprozessoranweisungen können an beliebigen Stellen stehen, # aber in der ersten Spalte, kein ';' am Ende der Zeile! Blöcke strukturieren den Code Deklarationen und Definitionen auf allen Ebenen möglich, aber nur innerhalb des Blocks gültig. Müssen vor den ersten Anweisungen stehen. Anweisungen, wie auch Deklarationen, enden mit ';' Hello World / Hinweise #include <stdio.h> #include <stdio.h> #include <stdio.h> main #include () <stdio.h> main (void) { void #include <stdio.h> { /* printf ("Hello World\n"); int main main (int (int argc argc,[,char char { int char*argv, *argv[] [, *envp) char *envp[]]]) printf ("Hello World\n"); } int main (argc, argv, envp) printf ("Hello World\n"); } */ int argc; return 1; char *argv; } main (int int argc, char *argv, char *envp) char *envp; { { printf ("Hello World\n"); printf ("Hello World\n"); return (1); return 1; } } 19.08.2010 | FP 5 | Kernphysik | M. Platz | 19 Hello World #include <stdio.h> Präprozessor Befehl "Datei einbinden". main () { printf ("Hello World\n"); } Hauptfunktion; Hier fängt die Programmausführung an. Diese Art der Definition schaltet die Überprüfung der Argumentenliste ab, es wird kein Rückgabewert erwartet. Funktionsaufruf; Deklaration in "stdio.h" (Standardbibliothek). 19.08.2010 | FP 5 | Kernphysik | M. Platz | 20 Compilieren (Linux) GNU C-Compiler (gcc): benutzer@rechner:~$ gcc <C-File> -o <Ausgabedatei> Genaue Überprüfung des C-Standards: benutzer@rechner:~$ gcc –Wall <C-File> -o <Ausgabedatei> hello_world.c:4: warning: return type defaults to 'int' hello_world.c: In function 'main': hello_world.c:6: warning: control reaches end of non-void function 19.08.2010 | FP 5 | Kernphysik | M. Platz | 21 Aufgaben Versuchen, die Fehler zu entfernen Mehrere hintereinander ausführen printf,printf-Anweisungen fprintf, sprintf, snprintf, vprintf, vfprintf, vsprintf, und die vsnprintf - formatted output conversion Ausgabe interpretieren. SYNOPSIS Benutzung von<stdio.h> Steuerzeichen (was bedeutet was?): #include \a, \b, \f, \n, \r, \t, \v, \? ,\ooo,\xhhh int printf(const char *format, ...); fprintf(FILE\', *stream, Escape int Sequenzen: \",\\ const char *format, ...); int sprintf(char *str, const char *format, ...); int printf snprintf(char *str, size_t size, const char *format, Mehr über (benutzer@rechner:~$ man 3...); printf) #include <stdarg.h> int int int int vprintf(const char *format, va_list ap); vfprintf(FILE *stream, const char *format, va_list ap); vsprintf(char *str, const char *format, va_list ap); vsnprintf(char *str, size_t size, const char *format, va_list ap); DESCRIPTION 19.08.2010 | FP 5 | Kernphysik | M. Platz | 22 Tag 2 Rechnen, Bedingungen, Schleifen Rechnen Addition i = a + b; i = i + x; i += x; Subtraktion i = a – b; i = i – x; i -= x; Multiplikation i = a * b; i = i * x; i *= x; Division i = a / b; i = i / x; i /= x; Inkrementieren i = i + 1; i += 1; i ++; ++i; Dekrementieren i = i – 1; i -= 1; i --; --i; Modulo i = a % b; i = i % x; i %= x; 19.08.2010 | FP 5 | Kernphysik | M. Platz | 24 Vergleiche Alle Vergleiche geben einen Boolschen Wert zurück. Der Typ BOOL ist in der Regel Betriebssystemabhängig und in <stddef.h> definiert Ist der Typ BOOL vorhanden, gibt es auch die symbolischen Konstanten FALSE TRUE (! FALSE d.h alles ungleich FALSE) Ist bei einem Vergleich Gleichheit festgestellt, ist das Ergebnis TRUE, sonst FALSE Für bedingte Code-Ausführung wird die if-else-Anweisung benutzt 19.08.2010 | FP 5 | Kernphysik | M. Platz | 25 If-Else #include <stdio.h> main() { char c; Bedingung c = getchar(); { if (c == ' '){ printf ("War ein SPACE\n"); } else { printf ("%c\n", c); } } 19.08.2010 | FP 5 | Kernphysik | M. Platz | 26 Ausführung wenn TRUE Ausführung wenn FALSE Vergleichsoperatoren AND && Ungleichheit != OR || Größer > NOT ! Kleiner < Größer Gleich >= Kleiner Gleich <= Gleichheit == 19.08.2010 | FP 5 | Kernphysik | M. Platz | 27 Weitere Möglichkeit Operator ?: Bedingung #include <stdio.h> #include <stdio.h> Zuweisung wenn wahr main() { if (a > b) { z = a; } else { z = b; } main() { z = (a > b) ? a : b; } Zuweisung wenn falsch } 19.08.2010 | FP 5 | Kernphysik | M. Platz | 28 Vorrang #include <stdio.h> main() { } #include <stdio.h> main() if (y = a > b || { a == 100 && b != { if ((y = a z = a; { } z else } { else z = b; { } z } } 19.08.2010 | FP 5 | Kernphysik | M. Platz | 29 0) > b) || ((a == 100) && (b != 0)) = a; = b; Schleifen Wiederholung einer bestimmten Funktionalität Kriterium für das Schleifenende Anzahl der Durchläufe Bestimmte Bedingungen sind erfüllt Die Sprache C bietet zwei Schleifentypen for-Schleife In der Regel wird diese Schleife bei einer definierten Anzahl von Durchläufen benutzt while-Schleife bzw. do-while Kombination Wird in der Regel für Schleifen benutzt, die durch Erfüllung von Bedingungen beendet werden Beide Schleifentypen sind prinzipiell austauschbar! 19.08.2010 | FP 5 | Kernphysik | M. Platz | 30 For-Schleife /* Umrechnung Fahrenheit in Celsius nach: °C = (5/9)(F-32) */ #include <stdio.h> Startwert Abbruchkriterium main() { unsigned int iF; Operation nach einem Schleifendurchgang for (iF=0; iF<=300; iF = iF + 20) { printf ("%3d %6.1f\n", iF, (5.0/9.0)*(iF-32)); } } 19.08.2010 | FP 5 | Kernphysik | M. Platz | 31 Intermezzo zu Variablen Deklaration Festlegen, um welchen Typ es sich handelt (kommt später) Definition Typ festlegen und Speicher reservieren Initialisieren Der definierten Variablen einen Wert zuweisen { { int i; // Definition int i = 0; /* Definition und Initialisierung*/ … i = 0; // Initialisierung … } 19.08.2010 | FP 5 | Kernphysik | M. Platz | 32 } Aufgaben (for-Schleife) Was passiert, wenn die Schleifenvariable nicht initialisiert wird Was passiert, wenn man (5.0/9.0) durch (5/9) Was kann man bei der for-Schleife alles weglassen? Kann die Schleifenvariable auch andere Typen haben (double, long)? 19.08.2010 | FP 5 | Kernphysik | M. Platz | 33 While-Schleife /* Umrechnung Fahrenheit in Celsius nach: °C = (5/9)(F-32) */ #include <stdio.h> Abbruch Kriterium main() { unsigned int iF = 0; Initialisierung und Inkrementierung an einer anderen Stelle while (iF<=300) { printf ("%3d %6.1f\n", iF, (5.0/9.0)*(iF-32)); iF+=20; } } 19.08.2010 | FP 5 | Kernphysik | M. Platz | 34 Do-While-Schleife /* Umrechnung Fahrenheit in Celsius nach: °C = (5/9)(F-32) */ #include <stdio.h> main() { unsigned int iF = 0; In dieser Kombination muss ein ';' am Ende der Schleife stehen! do { printf ("%3d %6.1f\n", iF, (5.0/9.0)*(iF-32)); iF+=20; } while (iF<=300); } 19.08.2010 | FP 5 | Kernphysik | M. Platz | 35 Aufgaben (while-Schleife) Tabelle von "unten" nach "oben" ausgeben In der Ausgabe noch eine Index (1.) anfügen Ausgabe einer Tabelle Celsius -> Fahrenheit Unterschied bei der Definition signed, unsigned? 19.08.2010 | FP 5 | Kernphysik | M. Platz | 36 Continue Anweisung Nur gültig in Schleifen Durch diesen Aufruf wird der Programmablauf am Anfang der Schleife fortgesetzt for (i=0; i<10; i++) { if (irgendeine Komische Bedingung) { continue; } …. } Ähnlich zur goto-Anweisung; wird bei klarer Programmierung nicht gebraucht ! 19.08.2010 | FP 5 | Kernphysik | M. Platz | 37 Break-Anweisung Beendet die übergeordnete Schleife while (TRUE) { if (irgendeine Komische Bedingung) { break; } …. } Oft durch ein sinnvolles Abbruchkriterium der Schleife vermeidbar; Bei höheren Verschachtelungsstufen kann es undurchsichtig sein! 19.08.2010 | FP 5 | Kernphysik | M. Platz | 38 Aufgaben Die ersten 100 Primzahlen berechnen lassen Eine Primzahl ist eine natürliche Zahl mit genau zwei natürlichen Zahlen als Teiler, nämlich der Zahl 1 und sich selbst Optimieren 2k + 1 19.08.2010 | FP 5 | Kernphysik | M. Platz | 39 Switch - case switch-case Anweisungen erlauben die Auswahl aus mehreren Alternativen In switch() wird der zu testende Wert angegeben case legt Marken fest, an denen die Programmausführung fortgesetzt wird, wenn der in der Marke angegebene konstante Wert mit dem in der switch()Anweisung übereinstimmt char c; Wert von Interesse c = getchar (); switch (c) Konstante { Auszuführender Code case '\r': case '\t': Abruch der switch()-Anweisung case ' ': printf ("Whitespace\n"); break; default: printf ("Zeichen"); break; } 19.08.2010 | FP 5 | Kernphysik | M. Platz | 40 Optionaler Ausdruck; Wenn keine case-Anweisung zutreffend ist, wird die Ausführung hier fortgesetzt Tag 3 Zeichen, Zeichenketten, Zeiger, Strukturen Zeichen Type für Zeichen: char Die tatsächliche Bit-Breite eines Typs ist nicht im C-Standard definiert, sondern systemabhängig Definition des Wertebereiches in limits.h (/usr/include/limits.h) In der Regel 8-Bit breit, Wertebereich -128 – 127 Gibt in der Regel den Code eines Zeichens im ASCII Standard an ASCII Standard enthält 128 Zeichen (33 Steuerzeichen, 95 druckbare Zeichen) Anmerkung: Auch die anderen Typen haben keine definierte Breite (oder Aufbau). 19.08.2010 | FP 5 | Kernphysik | M. Platz | 42 Aufgaben ASCII Tabelle der Druckbaren Zeichen ausgeben (ab Zeichen 32) Zeichen von 32 bis 255 ausgeben Zeichensatz ändern und Programm erneut ausführen ASCII Codes der Steuerzeichen aus der prinf()-Anweisung ausgeben 19.08.2010 | FP 5 | Kernphysik | M. Platz | 43 Zeichenketten Array aus Zeichen, letztes Zeichen '\0' #include <stdio.h> #include <stdlib.h> #include <string.h> main() { char szString_1[16]; char szString_2[] = "Hello World"; char szString_3[] = {'H','e','l','l','o',' ','W','o','r','l','d','\0'}; strcpy (szString_1, szString_2); if (! strcmp (szString_1, szString_3)) { printf ("Gleich\n"); } } 19.08.2010 | FP 5 | Kernphysik | M. Platz | 44 Array char szString[] = "Hello World"; Startadresse … 'H' 'e' 'l' 'l' 0xAF00 Index 0 1 'o' ' ' 'W' 'o' 'r' 'l' 'd' '\0' … 0xAF0B 2 … 11 char c; int iAddress; c = szString[2]; // c enthält jetzt 'l' iAddress = szString; /* iAddress enthält jetzt die Adresse des Strings im Arbeitsspeicher (0xAF00)*/ 19.08.2010 | FP 5 | Kernphysik | M. Platz | 45 Aufgaben Definition von strcpy() und strcmp() nachschlagen Inhalt des uninitialisierten char-Arrays ausgeben Inhalt des initialisierten char-Arrays ausgeben String in ein zu kleines Array kopieren Länge des Strings bestimmen 19.08.2010 | FP 5 | Kernphysik | M. Platz | 46 Pointer Zeiger auf einen Speicherbereich (Adresse) Inhaltsoperator #include <stdio.h> main() { char *pcTest; Der Zeiger hat immer die für das laufende System benötigte Bit-Breite, um eine Adresse zu speichern (32-Bit System Î 32 Bit). printf ("Adresse der Variablen: %4x\n", pcTest); printf ("Inhalt der Variablen: %i\n", *pcTest); //Uninitialisiert /* Werte Zuweisung */ Für den Inhalt des Pointers *pcTest = 'T'; } Soll mehr als ein Zeichen gespeichert werden, muss der entsprechende Speicher reserviert werden 19.08.2010 | FP 5 | Kernphysik | M. Platz | 47 wird die Bit-Breite reserviert, die durch die Definition gegeben ist (hier char). Arbeiten mit Adressen char szString_1[16]; char szString_2[] = "Hello World"; /* Definition von strcpy: Startadresse char* strcpy (char *str1, char *str2); */ strcpy (szString_1, szString_2); … 'H' 'e' 'l' 'l' 'o' ' ' 'W' 'o' 'r' 'l' 0xAF00 Address-Operator 'd' '\0' … 0xAF0B char szString_2[] = "Hello World"; char *pstrString_3; char *pstrWorld; pstrString_3 = szString_2; pstrWorld = &szString_2[6]; 19.08.2010 | FP 5 | Kernphysik | M. Platz | 48 Aufgaben Arbeiten mit Pointern Zuweisen von Adressen Beispiel von vorheriger Folie in lauffähiges Programm umsetzen Benutzung des Inhaltsoperator (*) zum Zugriff auf Speicherstellen Mit Hilfe von Pointer den Inhalt des Arrays ausgeben 19.08.2010 | FP 5 | Kernphysik | M. Platz | 49 Strukturen Zusammenfassung zusammengehörender Daten Z.B. Punkt Î Zusammenfassung von x- und y-Koordinate Beschreibung von Daten im Adressbereich Registermap (z.B. eines Mikrocontrollers - Kurs 3) struct point { int x; int y; } Member main() { struct point pt; struct point *pPt; pPt = &pt; pt.x = 10; pt.y = 20; pPt->x = 10; … } 19.08.2010 | FP 5 | Kernphysik | M. Platz | 50 Auswahl des Members Unions Möglichkeit zur Speicherung unterschiedlicher Datentypen in einem Speicherbereich Der Compiler überwacht die Größe des Speicherbereichs. Zugriff auf den falschen Datentyp sind implementierungsabhängig Zugriff gleich zu Strukturen union number { int iNum; double dbNum; char szNum[16]; } main() { union number Number; Number.iNum = 1; /* geht nicht: Number.szNum = 1; Geht: strcpy (Number.szNum, "1"); */ } 19.08.2010 | FP 5 | Kernphysik | M. Platz | 51 Typen Neue (eigene) Typen werden definiert mit typedef typedef unsigned char BYTE; typedef struct point { int x; int y; } POINT; Void funktion (void) { BYTE by; POINT pt; … } 19.08.2010 | FP 5 | Kernphysik | M. Platz | 52 Typ Definition Typ Name Funktionsaufrufe Eine Funktion kann erst aufgerufen werden, wenn sie deklariert wurde Funktionsargumente (Inhalt der Variablen) werden vor dem Aufruf kopiert D.h. man kann einen Wert an die Funktion übergeben, bekommt die Änderung aber nicht durch diese Variable zurück Rückgabe von Werten ist nur durch die return-Anweisung möglich Diese Einschränkung ist nur durch Pointer zu umgehen Werden Pointer als Funktionsparameter benutzt, wird die Adresse kopiert Man greift dann direkt auf den Speicher zu (der Inhalt wird nicht kopiert!) Beim Rücksprung der Funktion bleiben die Änderungen im Speicherbereich erhalten 19.08.2010 | FP 5 | Kernphysik | M. Platz | 53 Glossar Definition Festlegen des Typs einer Variablen und Reservierung von Speicher Deklaration Festlegen des Typs einer Variablen ohne Reservierung des Speichers Initialisierung Zuweisen des Wertes einer Variablen Funktionsargument Wert, der dem Funktionsaufruf übergeben wird Funktionsparameter Variable, die dem Funktionsaufruf übergeben wird 19.08.2010 | FP 5 | Kernphysik | M. Platz | 54 Aufgaben Eingabe von Text mit Hilfe von getchar Eingegebene Zeile in einem Puffer (Array) speichern Einfache Verschlüsselung (Zeichen + Offset) Eigene strcpy()-Funktion schreiben char *strcpy (char *str1, char *str2); Rückgabewert ist Zeiger auf das Ziel Eigene strcmp()-Funktion schreiben int strcmp (char* str1, char *str2); Rückgabewert 0 wenn gleich, sonst kleiner oder größer 0 Typ "Komplexe Zahl" definieren (a+bi) Funktionen zum Rechnen mit komplexen Zahlen schreiben Addition: (a+bi) + (c+di) = (a+c) +(b+d)i Multiplikation: (a+bi) * (c+di) = (ac – bd) + (ad+bc)i 19.08.2010 | FP 5 | Kernphysik | M. Platz | 55 Tag 4 Strukturiertes Programmieren Strukturen char char int short Startadresse typedef struct beispiel { char c1; char c2; int i; short s1; short s2; } 19.08.2010 | FP 5 | Kernphysik | M. Platz | 57 short Strukturiertes Programmieren Allgemeine Regeln Auf globale Variablen verzichten Möglichst kurze und übersichtliche Funktionen Sinnvolle Variablen-Namen Schwer verständliche Konstrukte vermeiden, auch wenn man es für genial hält Bei größeren Projekten Aufteilung des Programms auf mehrere C-Dateien Zusammengehörender Code/Variablen in eine Datei Möglichkeit eine eigene Bibliothek aufzubauen Möglichst gleich dokumentieren Kommentare vor den Funktionen, die Funktionalität, Parameter, Rückgabewerte und Spezialitäten beschreiben. 19.08.2010 | FP 5 | Kernphysik | M. Platz | 58 Präprozessor Vorstufe zum Compiler Einfügen von Dateien (#include) Definition von symbolischen Konstanten und Makros (#define) Vordefinierte Makros (__LINE__, __FILE__, __DATE__, __TIME__) Bedingungsabhängige Code-Generation (#if, #else, #ifdef, …) Erweiterte Compiler-Steuerung (#warning, #error, #pragma) 19.08.2010 | FP 5 | Kernphysik | M. Platz | 59 Präprozessor #include <stdio.h> #include "mydef.h" // Symbolische Konstante #define MAX_VALUE 255 //Makro #define ABS(A) ((A < 0) ? –A : A) void test void (int iValue) { #ifdef DEBUG printf ("Maximal zulässiger Wert: %i\n", MAX_VALUE); #endif if (iValue > MAX_VALUE) { printf ("Zu gross\n"); } … 19.08.2010 | FP 5 | Kernphysik | M. Platz | 60 Speicherklassen Variablen sind zunächst nur innerhalb des Blocks gültig, in dem sie definiert wurden. Definition ist die Festlegung des Typs und das Reservieren des benötigten Speichers Wird eine Variable in unterschiedlichen C-Dateien benötigt (ist selten der Fall), darf sie nicht in allen Dateien definiert werden Für jede Variable würde Speicher reserviert –> unterschiedliche Variablen (aber gleicher Name) Variable muss in allen Dateien deklariert werden (nur den Typ festlegen) und in einer Datei definiert. Deklaration einer Variablen für die Benutzung in unterschiedlichen Dateien mit dem Keyword extern extern gibt eine Speicherklasse an 19.08.2010 | FP 5 | Kernphysik | M. Platz | 61 Header-Dateien Header-Dateien (Endung .h) sind Dateien, in denen i.d.R. keine Code steht Dienen zum Deklarieren von Variablen und Funktionen Definieren von Makros und Konstanten Definieren eigener Typen, Unions Werden also benutzt, um Informationen, die in unterschiedlichen C-Dateien benötigt werden, zentral zusammenzufassen Header-Dateien sollten nur gemeinsam genutzte Information enthalten! 19.08.2010 | FP 5 | Kernphysik | M. Platz | 62 Beispiel test.h test.c #ifndef test_h #define test_h #include "test.h" #include "test.h" /* … #include <stdio.h> /* Globale Variable, die in allen Dateien, in denen test.h eingebunden wird, definiert wird */ int iVariable; /* Hiermit wird nur der Typ festgelegt, aber kein Speicher reserviert. */ extern int iGlobal; #endif 19.08.2010 | FP 5 | Kernphysik | M. Platz | 63 test2.c Hier wird iGlobal definiert. */ int iGlobal; … void test (void) { iGlobal = 1; iVariable = 0; …; } void test2 (void) { if (iGlobal == 1) { …; } // undefiniert if (iVariable == 0) { ; } …; } Speicherklassen II Variablen innerhalb eines Blocks werden ungültig, wenn der Block verlassen wird In seltenen Fällen kann es nötig sein, dass eine Variable den gespeicherten Wert behalten muss Beim erneuten Eintritt in den Block ist die Variable mit dem zuvor gespeicherten Wert wieder verfügbar Dafür dient die Speicherklasse static Globale statische Variablen sind nur innerhalb der C-Datei, in der sie definiert wurden, gültig 19.08.2010 | FP 5 | Kernphysik | M. Platz | 64 Aufgaben Benutzung der Speicherklasse static Implementierung einer Funktion, die die Anzahl ihrer Aufrufe protokolliert 19.08.2010 | FP 5 | Kernphysik | M. Platz | 65