Erste Schritte - cm.in.tum.de · C-Vorkurs TUM © 2018 O. Bergmann 3 Ein C-Programm im Emacs $...
Transcript of Erste Schritte - cm.in.tum.de · C-Vorkurs TUM © 2018 O. Bergmann 3 Ein C-Programm im Emacs $...
C-Vorkurs TUM © 2018 O. Bergmann 1
Erste Schritte
#include <stdio.h>
int main() { printf("Hello world!\n");}
● Speichern in hello.c● Übersetzen und zusammenbindencc -o hello hello.c
● Ausführen./hello→ Hello world!
C-Vorkurs TUM © 2018 O. Bergmann 2
Der Editor Emacs
Ein oder mehrere „Buffer“(= Arbeitsbereiche)
Menüleiste
Minibuffer: hier werdenKommandos für Emacseingegeben.
Mode-Zeile: Zeichenkodierung,Speicherzustand, Buffer-Name, Cursorposition im Buffer, Mode...
C-Vorkurs TUM © 2018 O. Bergmann 4
Einige Emacs-Kommandos● C-_: rückgängig● C-g: Abbruch● C-x C-c: Emacs beenden
● C-x C-f: Datei laden/erzeugen● C-x C-s: Datei speichern● C-x C-w: Datei unter anderem Namen
speichern● C-x b: Buffer wechseln● C-x C-b: Bufferliste● C-x k: aktuellen Buffer löschen● C-x 0: aktuelles Fenster löschen● C-x 1: anderes Fenster löschen● C-x o: Fenster wechseln
M: „Meta“ (ESC oder linke Alt-Taste)C: „Ctrl“ (linke Steuerungstaste)S: „Shift“ (linke Umstelltaste)
M-x: Kommando ausführen (z. B. M-x version)
● C-s: Vorwärtssuche im Buffer● C-k: aktuelle Zeile löschen● C-Leertaste:
Blockanfang markieren● M-w: Block kopieren● C-w: Block ausschneiden● C-y: Block einfügen
C-Vorkurs TUM © 2018 O. Bergmann 5
C-Compiler
● Default-Compiler: cccc -v→ gcc version 8.2.0 (Debian 8.2.0-7)
clang -v→ clang version 6.0.1-9 ...
● Im Zweifel gccssh uraltrechner "gcc -v"→ gcc version 4.6.3 (GCC)
Im Folgendenimmer gcc(Mac OS: clang)
C-Vorkurs TUM © 2018 O. Bergmann 6
#include <stdio.h>
int hello() { printf("Hello world!\n");
}
Compilerflags
gcc hello.c./a.out→ Hello world!
gcc -o hello hello.c./hello→ Hello world!
gcc –Wall -Wextra -o hello.o hello.chello.c: In function ‘hello’:hello.c:5:1: warning: control reaches end of non-void function [-Wreturn-type]
#include <stdio.h>
int hello() { printf("Hello world!\n"); return 0;}
C-Vorkurs TUM © 2018 O. Bergmann 7
Überblick
● Dateinamenname.c name.h
● Sprachmittel– Ausdruck (expression)1 1 + 2 value value = 1 + 2 a = b = c
– Anweisung (statement)int value;value = 7 + 1;return -12;
C-Vorkurs TUM © 2018 O. Bergmann 8
Funktionen
int power(int, int);
int main() { power(2, 5); return 0;}
int power(int base, int n) { int i, p = 1; for (i = 1; i <= n; i++) { p = p * base; } return p;}
Deklaration
DefinitionAufruf
C-Vorkurs TUM © 2018 O. Bergmann 9
Manuals
#include <stdio.h>#include <math.h>
int main() { double x = 0; while (x < M_PI_2) { printf("sin(%g) = %g\n", x, sin(x)); x += 0.05; } return 0;}
gcc -o sine.o -c sine.c(→ sine.o)
gcc -o sine sine.o -lm(→ sine)
SIN(3) Linux Programmer's Manual
NAME sin, sinf, sinl - sine function
SYNOPSIS #include <math.h>
double sin(double x); ... Link with -lm.
DESCRIPTION The sin() function returns the sine of x, where ...
RETURN VALUE On success, these functions return the sine of x.
If x is a NaN, a NaN is returned.
If x is positive infinity or negative infinity, ...
ERRORS See math_error(7) for information ... The following errors can occur: ...CONFORMING TO C99, POSIX.1-2001...
BUGS Before version 2.10, the glibc implementation...
SEE ALSO acos(3), asin(3), atan(3), atan2(3), cos(3), ...
C-Vorkurs TUM © 2018 O. Bergmann 10
Standardausgabe
#include <stdio.h>
int power(int, int);
int main() { printf("Ergebnis: %d\n", power(2, 5)); return 0;}
int power(int base, int n) {...}
Header-Dateieinbinden
Zeilenumbruch(UNIX)
Formatstring
C-Vorkurs TUM © 2018 O. Bergmann 11
printf#include <stdio.h>
int printf(const char *format, ...);
printf("Hallo");printf("%s\n", "Hallo");
printf("%d", 42);printf("%08d", 1);printf("0x%04x", 42);printf("%p", main);printf("%12.4f", 17.3);printf("%12.*f", 4, 17.3);printf("%2$12.*1$f", 4, 17.3);
/* nicht Null-terminiert! */char huhu[] = { 0x68, 0x75, 0x68, 0x75 };
printf("%.*s", (int)sizeof(huhu), huhu);
C-Vorkurs TUM © 2018 O. Bergmann 12
Kommentare
● Sind Bestandteil eines Programms– Andere verstehen den eigenen Code– Man selbst versteht den eigenen Code
● Einzeilig: // Kommentar bis Zeilenende
● alternative Form: /* ... */– Kann über mehrere Zeilen gehen– Kann nicht geschachtelt werden– Gute Editoren helfen beim „Schachteln“M-x comment-regionM-x uncomment-region
C-Vorkurs TUM © 2018 O. Bergmann 13
doxygen
(siehe javadoc)
/** * Sends @p length bytes from @p data somewhere. * * @param data The data to send. * @param length The actual length of @p data. * @return The number of bytes that have been * sent. */size_t send_bytes(char *data, size_t length);
C-Vorkurs TUM © 2018 O. Bergmann 14
Grunddatentypen
● Interpretation von Speicher (ia32)
● Bytes mit jeweils 8 Bit (Bits nicht einzeln adressierbar)
● Längere Datenobjekte (Wörter)● Semantik?● z. B. Reihenfolge der Bytes in einem Wort (Byte-order)
00000000 00000000 00000000 00000001
C-Vorkurs TUM © 2018 O. Bergmann 15
Arten von Grunddatentypen● Ganze Zahlen
– [signed|unsigned] char
– [signed|unsigned] [short|long[long]] int
– wchar_t
– Enum-Typen
● Gleitkomma-Typen (Floating Point)– float
– [long] double
● void
C-Vorkurs TUM © 2018 O. Bergmann 16
Speicherbedarf der Grunddatentypen
# Bytes signed unsigned
0 void
1 char
? wchar_t
1 signed char unsigned charh ≥ 2 [signed] short [int] unsigned short [int]i ≥ h [signed] int unsigned [int]j ≥ i [signed] long [int] unsigned long [int]
k ≥ 2 float —m ≥ k double —n ≥ m long double —
C-Vorkurs TUM © 2018 O. Bergmann 17
Größen der Datentypen heute
● in Bibliotheken definiert– size_t: unsigned, passend für Größe eines Objekts
– ptrdiff_t: signed, passend für Differenz zwischen Zeigern
– intN_t, uintN_t: für Variablen fester Größe(optional, N { 8, 16, 32, 64 })∈
Typ anzunehmen ILP32 LP64
char [≥] 8 Bits 8 Bits 8 Bits
short ≥ 16 Bits 16 Bits 16 Bits
int short ≤ int ≤ long 32 Bits 32 Bits
long ≥ 32 Bits 32 Bits 64 Bits
#include <stdint.h>
C-Vorkurs TUM © 2018 O. Bergmann 18
Konstanten
● Integerzahlen1234 (int)123456789L 0l (long)1234u (unsigned)123456789Ul 0uL (unsigned long)0777 0777u (oktal)0x3F 0x3FL (hexadezimal)
● Gleitkommazahlen1234.5 1e-6 (double)1234.5f 1e-6F (float)1234.5L 1e-6l (long double)
C-Vorkurs TUM © 2018 O. Bergmann 19
Character-Konstanten
'a' '9' '\n' '\t' '\'' '\0''\177' '\7' (oktal) '\xb' (hexadezimal)
Bedeutung Kürzel C-Escape
new-line NL (LF) \n
horizontal tab HT \t
carriage return CR \r
alert BEL \a
backslash \ \\
single quote ' \'
double quote „ \“
octal number ooo \ooo
hex number hhh \xhhh
Rechnen mit chars:'a' + 1 == 'b'→ Asciitabelle (nicht sehr portabel)
C-Vorkurs TUM © 2018 O. Bergmann 20
String-Konstanten
"Hello world\n"
"Hello" " world\n"
"" Leerstring (ein Null-Byte)
H eH l l o w o r l d \n \0
Terminiert mit Null-Byte!
C-Vorkurs TUM © 2018 O. Bergmann 21
Variablendeklarationen
● Buchstaben, Unterstrich, Ziffern
● Buchstabe oder Unterstrichals erstes Zeichen
● Groß-/Kleinschreibung● Keine Schlüsselwörter
(if, int, ...)
● Immer vor Benutzung● Typ plus Liste von
Variablen
Namen Deklarationen
int lower, upper;char c, buf[100];unsigned counter;char space = ' ';int j = 0, k = 8;unsigned m = MAXLINE + 1;
C-Vorkurs TUM © 2018 O. Bergmann 22
Read-only Variablen
● Schlüsselwort const const double pi = 3.14159265359; const int off = 0, running = 1;
● Enumeration enum { off, idle, running };anstatt const int off = 0; const int idle = 1; const int running = 2;
C-Vorkurs TUM © 2018 O. Bergmann 23
Aufzählungstypen
enum state { off, idle, running };enum months { jan = 1, feb, mar, ... };
error
i == 2stout
error
enum beer { ale, bitter, lager, stout };enum juice { orange, apple, grapefruit };
enum beer carlsberg = lager;enum juice granini = orange;
carlsberg = orange;int i = lager;carlsberg++;
if (carlsberg == orange) { ...}
Typdefinition
Benutzung
muss in intpassen
C-Vorkurs TUM © 2018 O. Bergmann 24
typedef: neue Typbezeichner
enum state { off, idle, running };enum months { jan = 1, feb, mar, ... };
enum beer { ale, bitter, lager, stout };
typedef enum beer irgendein_typ;typedef enum beer beer;
enum beer b1 = lager;irgendein_typ b2 = b1;beer b3 = ++b1;
Typdefinition
Benutzung
in C++nicht erlaubt
C-Vorkurs TUM © 2018 O. Bergmann 25
typedef: neue Typbezeichner
typedef enum { ale, bitter, lager, stout } beer;
beer b3 = ale;
Typdefinition
Benutzung
anonymerAufzählungstyp
neuer Bezeichnerfür anonymen Typ
analog mit struct etc. (später...)
C-Vorkurs TUM © 2018 O. Bergmann 26
Operationen und Ausdrücke● Operation, Operand 3 + 4 (binär) -2 (unär)
● Arithmetische Operatoren– Grundrechenarten: + - * /
– Modulo: %schneidet ab zwischen ganzen Zahlenerzeugt Gleitkomma zwischen Gleitkommazahlen: 7/2 → 3 7.0/2 → 3.5
C-Vorkurs TUM © 2018 O. Bergmann 27
Typumwandlung
● Arithmetische Operationen nur für int oder größer definiert● integer promotion
→ Umwandlung der Operanden nach int([[un]signed] char, short)
→ oder nach unsigned int(unsigned short, enum, wchar_t)
● Ausdruck mit Operanden unterschiedlichen Typs– Automatische Typumwandlung → gemeinsamer Typ, möglichst ohne
Informationsverlust● Umtypungen in arithmetischen Ausdrücken
– „niedriger“ Typ wird zu „höherem“ konvertiert
– (ganzzahlig) → float → double → long double
– int → unsigned → long → unsigned long
C-Vorkurs TUM © 2018 O. Bergmann 28
Noch mehr Typumwandlungen● Zuweisungint i = 1234;char c;c = i;
● Funktionsaufrufdouble sqrt(double);...double result = sqrt(2);
● cast-Operator– Explizite Typumwandlung: (Typname) Ausdruckdouble result = sqrt((double)2);
c → -46
Häufiges Idiom (nicht portabel!):zahl = zahl * 10 + (zeichen – '0');
C-Vorkurs TUM © 2018 O. Bergmann 29
Relationale und logische Operatoren
● Ergebnis ist wahr (1) oder falsch (0)
● Relational: > >= < <= == !=
● Logisch: && (und) || (oder)
● Auswertung bricht ab, wenn Ergebnis klarwhile (i < MAXBUF && buf[i] != '\0') { i++;}
● Unäre Negation: !!!X ≡ X != 0
Wäre für i ≥ MAXBUF illegal
0 && X 0
1 && X X
0 || X X
1 || X 1
if (!expression) ≡ if (expression == 0)
C-Vorkurs TUM © 2018 O. Bergmann 30
Bitweise Operatoren
● Bits setzenx = x | BITS x = x | (1 << BITNUM)
● Bits ausmaskieren (löschen)x = x & 0177 x = x & ~0xF
& bitweises UND| bitweises ODER^ bitweises XOR<< Linksshift (füllt mit 0 auf)>> Rechtsshift (füllt mit 0 auf)~ bitweises Komplement (unär)
Achtung!
&& und || ≢ & und |
(1 & 2) == 0(1 && 2) == 1
C-Vorkurs TUM © 2018 O. Bergmann 31
Beispiel: gesetzte Bits zählen
int bitcount(unsigned x) { int count; for (count = 0; x != 0; x = x >> 1) { if (x & 1) { count++; } } return count;}
C-Vorkurs TUM © 2018 O. Bergmann 32
Syntaktischer Zucker: Zuweisungen
expr1 = expr1 op expr2 wird zu expr1 op= expr2
(op ist beliebiger zweistelliger arithmetischer oder logischer Operator)i = i + 2 i += 2b = b << 1 b <<= 1b = b & 0177 b &= 0177x[1] = x[1] * (y + 1) x[1] *= y + 1
table[values[p1+p2] + values[p3+p4]] += 2
C-Vorkurs TUM © 2018 O. Bergmann 33
Syntaktischer Zucker: Bedingter Ausdruck
expr1 ? expr2 : expr3
→ Abkürzung für if-else-Statement
max = (a > b) ? a : b;
printf("%zu zeile%s ausgegeben\n", n, (n == 1) ? "" : "n");
C-Vorkurs TUM © 2018 O. Bergmann 34
Noch mehr Zucker: Inkrement und Dekrement
● Als Präfix: ++n, --n
n wird vor Benutzung um 1 erhöht bzw. verringert● Als Postfix: n++, n--n wird nach Benutzung um 1 erhöht bzw. verringertn = 3;x = n++; /* x == 3, n == 4 */x = ++n; /* x == 5, n == 5 */
● Operand muss lvalue sein
(n+1)++ /* error */
„[...] ein Ausdruck (mit Typ ≠ void), der [...] ein Objekt bezeichnet.“
C-Vorkurs TUM © 2018 O. Bergmann 35
Statements und Blöcke
● Statement: terminiert mit SemikolonLeeres statement: ;
● Block: umgeben von { und } (ohne Semikolon)leerer Block: {}
● Deklarationen nur am Beginneines Blocks erlaubt
voidf(int i) { int j; if (i == 0) { int k, j; ... } ...}
C-Vorkurs TUM © 2018 O. Bergmann 36
Kontrollfluss: if-else
● Optionaler else-Teil
● statement: einzelnes Statement oder Block
● if ermittelt booleschen Wert für Ausdruck
if (Ausdruck) statement
1else statement
2
if (Ausdruck) ≡ if (Ausdruck != 0)
C-Vorkurs TUM © 2018 O. Bergmann 37
Kontrollfluss: if-else und switch
if (option == 'b') statementelse if (option == 'h') statementelse if (option == 'v') statementelse statement /* default */
switch (option) {case 'b': statementcase 'h': statementcase 'v': statementdefault: statement}
C-Vorkurs TUM © 2018 O. Bergmann 38
Kontrollfluss: if-else und switch
switch (Ausdruck) {case konst. Ausdruck: statementscase konst. Ausdruck: statementscase konst. Ausdruck: statementsdefault: statements}
● case-Labels sind konstante Ausdrücke
● Optionaler default-Zweig
● case fällt durch!→ Beenden mit break
switch (option) {case 'b': do_b(); break;case 'v': { verbose = optarg; break;}case 'h': /* fall through */default: show_help(); exit(EXIT_FAILURE);}
C-Vorkurs TUM © 2018 O. Bergmann 39
Kontrollfluss:while/do-while● while:
wiederholt statement, solange Ausdruck wahr ist(d. h. ungleich 0)
● do-while:– Abbruchbedingung am Ende
→ mindestens eine Ausführung– Verwechslungsgefahr mit leerer while-Schleife, z. B. (schlechter Stil)while (*p++);
while (Ausdruck) statement
do statementwhile (Ausdruck);
C-Vorkurs TUM © 2018 O. Bergmann 40
Kontrollfluss: for
● wiederholt statement2, bis Ausdr1 erfüllt
for (stmnt1 Ausdr
1; Ausdr
2)
statement2
int i;for (i = 0; i < 10; i++) { printf("%d\n", i);}
● Ausdr1, Ausdr2 optional(→ Ausdr1 wahr)
● Endlosschleife mit stmnt1 ;for (;;)
C-Vorkurs TUM © 2018 O. Bergmann 41
Kontrollfluss: break
● Verlässt switch-statement
● Verlässt innerstes umgebendes for, while, do
for (...) { do_someting(); if (condition) { break; } do_something_else();}
C-Vorkurs TUM © 2018 O. Bergmann 42
Kontrollfluss: continue
● Springt zur nächsten Schleifeniteration● Test der Bedingung (for, while, do)
● Inkrementierung (for)
for (i = 0; i < 15; i++) { if (a[i] == 0) { continue; } process(a[i]);}
C-Vorkurs TUM © 2018 O. Bergmann 43
Kontrollfluss: goto
goto Label; ...Label: ...
● Setzt Programmausführung bei Label fort– Gültiger Bezeichner, gefolgt von
einem Doppelpunkt– Lokal zu aktueller Funktion
● Verpönt
● Nützlich zur Fehlerbehandlung in Parsern u. ä.
E. W. Dijkstra: Letters to the editor: go to statement consideredharmful. In: Comunications of the ACM, 11 (3), 1968, pp. 147–148.
C-Vorkurs TUM © 2018 O. Bergmann 44
Noch etwas Zucker: Komma-Operator
● Ausdruck1, Ausdruck2, Ausdruck3, ...
● Auswertung von links nach rechts● Ergebnis ist Wert des letzten Ausdrucks● Hauptanwendung im Kopf von for-Schleifen:void reverse_string(char s[]) { int i, j; for (i = 0, j = strlen(s) - 1; i < j; i++, j--) { char c = s[i]; s[i] = s[j]; s[j] = c; }
● Kein Komma-Operator in der Argumentliste beim Funktionsaufruf!
C-Vorkurs TUM © 2018 O. Bergmann 45
Funktionsdefinition
● Returntyp ist void oder ein bekannter Typ außer Array(keine Angabe → int)
● Parameterliste ist void oder eine Liste von Typ/Bezeichner-Paarenvoid stop(void) oder void stop()size_t substr(char s[], size_t from, size_t to)
● Schlüsselwort return– Verlässt Funktion– Argument muss zu Returntyp passen– Kein return am Ende notwendig für Returntyp void
Returntyp Funktionsname (Parameterliste) { statements}
void f(int i) { if (i < 0) return;}
int g(void) { return 42;}
C-Vorkurs TUM © 2018 O. Bergmann 46
Funktionsdeklarationen● Funktion muss deklariert werden, wenn
– Definition in einer anderen Quelldatei ist als der Aufruf– Aufruf vor der Definition erfolgt
● Deklaration teilt aufrufender Funktion den Returntyp mit– Verwendung des Ergebnisses– Überprüfung der Argumente durch den Compiler– Umtypung der Argumente bei Aufruf
● Wichtig für getrennte Übersetzung● Deklaration und Definition müssen übereinstimmen● Funktionsdeklaration (Prototyp)unsigned random(void); double pow(double, double);
● Bezeichner in Prototyp erlaubt: double pow(double x, double y)
double r;...r = pow(2, 10);
C-Vorkurs TUM © 2018 O. Bergmann 47
Lokale und globale Variablen● Lokale (automatische) Variablen
– Nur in umgebendem Block sichtbar (z. B. Funktion)– Nach Verlassen des Blocks zerstört– Nicht initialisiert
● Globale Variablen– Außerhalb von Funktionen deklariert– Sichtbar von Deklaration bis zum Ende der Quelldatei– Sichtbar in allen geschachtelten Blöcken (z. B. Funktionen)– Lebendig bis Programmtermination– Globale Variablen sind mit Null initialisiert
● Funktionen sind immer global
int k;
int f(int i) { int j; return j;}
int main() { return k;}
Sichtbarkeit von jLebensdauer von jj ist nicht initialisiert!
Sichtbarkeit von kLebensdauer von kk ist mit 0 initialisiert
C-Vorkurs TUM © 2018 O. Bergmann 48
Beispiel: Sichtbarkeit
const int maxstack = 100;
void search(int i);
int main() { search(15);}
void search(int i) { int j = 0;
while (j != i) { ... { float j; ... } }}
inneres j überdecktdas äußere
Lebensdauer von j
Sichtbarkeit von j
Sichtbarkeit von search()
C-Vorkurs TUM © 2018 O. Bergmann 49
Extern-Deklaration
● Deklariert eine Variable vor ihrer Benutzungextern int size;
● Nötig, wenn Variable in einer anderen Quelldatei definiert● Macht Typ der Variable bekannt
– Compiler legt keinen Speicherplatz an– Keine Initialisierung– Global oder lokal
● Variablendefinition wie gewohntint size = 100;– Nur eine Definition erlaubt– Veliebig viele extern-Deklarationen
● Funktionsdeklarationen sind immer extern (extern redundant)
C-Vorkurs TUM © 2018 O. Bergmann 50
Statische Variablen
● Globale statische Variablen– sichtbar nur bis Ende der Datei– In anderen Dateien nicht sichtbar/importierbar– Ziel: Modularisierung; Vermeidung von Namenskonfliktenconst int maxstack = 100;static int stack[maxstack], sptr = 0;
● Lokale statische Variablen– Sichtbar wie automatische
lokale Variablen– Bestehen auch nach Verlassen
des Blocks– Mit Null initialisiert
myobjectptr singleton() { static myobjectptr objp;
if (!objp) { objp = create_object(); }
return objp;}
C-Vorkurs TUM © 2018 O. Bergmann 51
Zusammenfassung: Sichtbarkeit und Lebensdauer
Speicher-klasse
Sichtbarkeit Lebensdauer
globalextern unbegrenzt unbegrenzt
static Datei unbegrenzt
lokalauto Block bis Blockende
static Block unbegrenzt
häufig genutzte Variablen optional in Prozessorregistern
C-Vorkurs TUM © 2018 O. Bergmann 52
Register-Variablen
● Bei automatischen Variablen und Funktionsparametern● Hinweis an den Compiler
– Variable wird oft benutzt– Maschinenregister soll benutzt werden
● Darf vom Compiler ignoriert werden● Bestimmte Operationen auf register-Variablen nicht
möglich
void f(register unsigned u) { register int i, j; ...}
C-Vorkurs TUM © 2018 O. Bergmann 53
Typqualifizierer
● const:Konstante, kann nicht vom Programmcode geändert werden
● volatile:Wert kann sich durch Programm-externe Effekte ändern (Seiteneffekt)
extern const volatile int real_time_clock;
C-Vorkurs TUM © 2018 O. Bergmann 55
Modularisierung
● Größere Projekte auf mehrere Quelldateien aufteilen– Übersichtlicher– Ermöglicht paralleles Arbeiten
● Nur geänderte Teile neu übersetzen● Linker fügt Teile zu ausführbarem Programm zusammen
main.c
util.c
list.c
main.o
util.o
list.o
gcc -c
gcc -c
gcc -c
prog
Bibliotheken
gcc main.o util.o list.o -lBibliothek -o prog
C-Vorkurs TUM © 2018 O. Bergmann 56
Modularisierung
main.c
util.c
list.c
main.o
util.o
list.o
gcc -c
gcc -c
gcc -c
prog
Bibliotheken
gcc main.o util.o list.o -lBibliothek -o prog
VorverarbeitenÜbersetzenOptimieren
Zusammenbinden
PräprozessorCompiler + Optimizer+ Assembler
Linker
GCC
C-Vorkurs TUM © 2018 O. Bergmann 57
Der Linker
● ld– Eingabe: Objektdateien, Bibliotheken– Ausgabe: ausführbares Programm– Bindet Eingabedateien zusammen und löst Referenzen auf
● Objektdateien– plattformspezifischer Maschinencode– Nicht ausführbar, enthalten u. U. nicht aufgelöste
Referenzen● Bibliotheken
– Statisch oder dynamisch („shared“)
a.out, .exe
Endung .o
Endung .a, .so
C-Vorkurs TUM © 2018 O. Bergmann 58
Symbole
● Alle verwendeten Symbole müssen aufgelöst werden
● Jedes Symbol darf nur einmal definiert sein#include <stdio.h>#include <math.h>
int main() { double x = 0; while (x < M_PI_2) { printf("sin(%g) = %g\n", x, sin(x)); x += 0.05; } return 0;}
gcc -o sine.o -c sine.c(→ sine.o)
gcc -o sine sine.o -lm(→ sine)
gcc -o sine sine.o... undefined reference to 'sin'collect2: error: ld returned ...
Einbinden von libm.a für sin()→ sonst Fehler
C-Vorkurs TUM © 2018 O. Bergmann 59
Symboltabellen anschauennm sine.o
00000000 T main U printf U sin
objdump -t sine.o
...00000000 g F .text 0000007f main *UND* 00000000 printf *UND* 00000000 sin
C-Vorkurs TUM © 2018 O. Bergmann 60
Getrennte Übersetzung
● Einzelne Dateien übersetzen (gcc -c ...)
● Können Symbole aus anderen Dateien benutzen– Deklaration vor jeder Benutzung erforderlich– Alle Deklarationen müssen konsistent sein– Deklarationen müssen konsistent mit Definition sein– Jedes Objekt muss genau einmal definiert werden
int foo = 12;
int bar(double d) { ...}
datei1.c
extern int foo;int bar(double d);
void baz() { foo = bar(1.0);}
datei2.c
C-Vorkurs TUM © 2018 O. Bergmann 61
Fehlerquellen (1)
● Typische Fehler(1) mehr als eine Definition(2) Definition und Deklaration inkonsistent(3) keine Definition
● Fehlererkennung
– Compiler sieht jeweils nur eine Quelldatei
– (1) und (3) werden vom Linker erkannt
– (2) nicht →Absturz zur Laufzeit möglich!
int foo = 12;
char b[10];
extern int c;
datei1.c
int foo;
extern char *b;
extern int c;
datei2.c
(1)(2)(3)
C-Vorkurs TUM © 2018 O. Bergmann 62
Fehlerquellen
● Typische Fehler(1) mehr als eine Definition(2) Definition und Deklaration inkonsistent(3) keine Definition(4) Definition und Deklaration inkonsistent
● Fehlererkennung
– Compiler sieht jeweils nur eine Quelldatei
– (1) und (3) werden vom Linker erkannt
– (2) und (4) nicht→ Absturz zur Laufzeit möglich!
int foo = 12;
char b[10];
extern int c;
int f(int i) {...}int g() {...}
datei1.cint foo;
extern char *b;
extern int c;
int f(double);char *g();
datei2.c
(1)(2)(3)(4)(4)
C-Vorkurs TUM © 2018 O. Bergmann 63
Header-Dateien
● Ziel: Konsistente Deklarationen→ Schnittstelle und Implementierung trennen
struct point { double x,y};
void plot(struct point p);
int f(int i);
#include "myplot.h"
void plot(struct point p) { ...}
#include "myplot.h"
int main() { struct point p1 = { 1.0, 1.0 }; plot(p1);}
myplot.h myplot.c
main.c
C-Vorkurs TUM © 2018 O. Bergmann 64
Was gehört in Header-Dateien?● Datendeklarationen● Funktionsdeklarationen● Typdefinitionen● inline-Definitionen● Aufzählungstypen● Präprozessoranweisungen● Nicht hinein gehören
– Datendefinitionen– Funktionsdefinitionen
extern int v;
int f(double);
struct coord { int x, y };
inline int max(int a, int b) {...}
enum state { on, off };
int v;int f() {...}
C-Vorkurs TUM © 2018 O. Bergmann 65
Präprozessoranweisungen (1)
#include– Rein textuelle Ersetzung– Compiler sieht nur fertige Übersetzungseinheiten
#define– Makro– Textuelle Ersetzung, optional mit Parametern
#undef– Präprozessprsymbole entfernen
#include <stdio.>#include "mplot.h"
#define PI 3.141#define max(a,b) \ ((a) > (b) ? (a) : (b))
#undef max#undef HAVE_TIME_H
C-Vorkurs TUM © 2018 O. Bergmann 66
Einschub: Seiteneffekte von Makros
● Makro-Parameter werden textuell ersetzt● Beispiel: mehrfaches Ausführen von ++n● Abhilfe:inline-Funktionen
#define max(a,b) ((a) > (b) ? (a) : (b))
...{ int k, n = 13; k = max(++n, 4); /* ((++n) > (4) ? (++n) : (4)) */}
inline intmax(int a, int b) { return a > b ? a : b;}
C-Vorkurs TUM © 2018 O. Bergmann 67
Noch mehr Seiteneffekte von Makros
● Makro-Parameter werden textuell ersetzt● Beispiel: Prioritäten von Operatoren● Abhilfe: Klammern (oder inline-
Funktionen)
#define sq(x) x * x /* falsch */
...{ double r; r = sq(y + 1); /* == y + 1 * y + 1 */}
#define sq(x) ((x) * (x))
C-Vorkurs TUM © 2018 O. Bergmann 68
Präprozessoranweisungen (2)
#if, #ifdef, #ifndef
– Bedingter Abschnitt (bis #endif)
– #ifdef X ≡ #if defined(X)
– Optional #else, #elif
#error– Beendet Übersetzung
mit Fehler
#pragma– Steuert Compiler-Spezifika
#if HAVE_SYS_TIME_Hr = gettimeofday(...);#else#error "no gettimeofday"#endif
#pragma STDC FP_CONTRACT OFF
C-Vorkurs TUM © 2018 O. Bergmann 69
Benutzung von Header-Dateien● Nach dem Ändern alle abhängigen Dateien neu
übersetzen (→ make verwenden)● „eigene“ Headerdatei einbinden
– Compiler kann Deklarationen gegen Definitionen prüfen
● Geschachtelte #includes eher selten→ Mehrfachdefinitionen möglich– Üblich: eine Headerdatei pro Quelldatei– Eventuall global Definitionen in eigener Headerdatei
→ config.h
C-Vorkurs TUM © 2018 O. Bergmann 70
Organisation von Headerdateien #define LIBDIR "/usr/local/lib"
#define VERSION 3#define HAVE_SYS_TIME_H 1
typedef struct buf_t { size_t size; char data[];} buf_t;
buf_t *buf_create(size_t size);void buf_delete(buf_t *);
config.h
buf.h
void error(char *);
error.h
#include <stdio.h>#include "config.h"#include "error.h"
voiderror(char *msg) {...} error.c
#include "config.h"#include "error.h"#include "buf.h"
buf_t *buf_create(size_t size) { ...} buf.c
C-Vorkurs TUM © 2018 O. Bergmann 71
Zyklische Abhängigkeiten vermeiden
#include "other_header.h"...
my_header.h
#include "my_header.h"...
other_header.h
#ifndef MY_HEADER_H#define MY_HEADER_H 1
#endif /* MY_HEADER_H */
#ifndef OTHER_HEADER_H#define OTHER_HEADER_H 1
#endif /* OTHER_HEADER_H */
C-Vorkurs TUM © 2018 O. Bergmann 72
Compilerpässe
datei.c tmp datei.s datei.o
includes
prog
Bibliotheken
Objekt-dateien
gcc -Egcc -S
gcc -c
gcc *.o -libsPräprozessorPräprozessor+ Compiler
Präprozessor+ Compiler+ Assembler Linker
C-Vorkurs TUM © 2018 O. Bergmann 73
gcc-Flags–E Präprozessor–S Präprozessor und Compiler–c Präprozessor und Compiler und Assembler–O Optimizer einschalten (üblich: –O2)–v Einzelne Pässe, Optionen und Argumente anzeigen–Wall Viele Warnungen ausgeben–Wextra Weitere wichtige Warnungen–g Debug-Symbole einfügen (→ gdb)–o xxx Linker: Ausgabedatei xxx anlegen (sonst a.out)–lxxx Linker: mit Bibliothek xxx linken–Ixxx Präprozessor: Verzeichnis xxx in den Suchpfad aufnehmen-Lxxx Linker: Verzeichnis xxx in den Suchpfad aufnehmen
C-Vorkurs TUM © 2018 O. Bergmann 82
Statische Datenstrukturen
● Basis-Datentypen (int, char, float, ...)● Zusammengesetzte Datentypen (struct, union)● Arrays
● Größe und Speicherbedarf sind bei Übersetzung bekannt
● Bekannte Position im Adressraum● Linker kann Adresse direkt in Programmcode
eintragen
C-Vorkurs TUM © 2018 O. Bergmann 83
0x400040x40000
0x400080x4000c
0x400140x40010
0x400180x4001c
0x400240x40020
0x400280x4002c
0x400340x40030
0x400380x4003c
0x400440x40040
0x400480x4004c
0x400540x40050
0x400580x4005c
0x400640x40060
0x400680x4006c
0x400740x40070
0x400780x4007c
0x400840x40080
0x400880x4008c
0x400940x40090
0x400980x4009c
0x400a40x400a0
0x400a80x400ac
0x400b40x400b0
0x400b80x400bc
int i;
Programm in Maschinensprache
feste Position von i im Speicher
C-Vorkurs TUM © 2018 O. Bergmann 84
Repräsentation auf Maschinenebene
i=i+7;
lw $t0,i # Load i
addi $t0,$t0,7 # i=i+7
sw $t0,i # Store i
ALU kann nur mit Registern arbeiten
lw $t0,0x40040 # Load i
addi $t0,$t0,7 # i=i+7
sw $t0,0x40040 # Store i
keine Variablen in Maschinensprache
Beispiele in MIPS32-Assembler
C-Vorkurs TUM © 2018 O. Bergmann 85
i=i+7;
0x400040x40000
0x400080x4000c
0x400140x40010
0x400180x4001c
0x400240x40020
0x400280x4002c
0x400340x40030
0x400380x4003c
0x400440x40040
0x400480x4004c
0x400540x40050
0x400580x4005c
0x400640x40060
0x400680x4006c
0x400740x40070
0x400780x4007c
0x400840x40080
0x400880x4008c
0x400940x40090
0x400980x4009c
0x400a40x400a0
0x400a80x400ac
0x400b40x400b0
0x400b80x400bc
7
C-Vorkurs TUM © 2018 O. Bergmann 86
0x400040x40000
0x400080x4000c
0x400140x40010
0x400180x4001c
0x400240x40020
0x400280x4002c
0x400340x40030
0x400380x4003c
0x400440x40040
0x400480x4004c
0x400540x40050
0x400580x4005c
0x400640x40060
0x400680x4006c
0x400740x40070
0x400780x4007c
0x400840x40080
0x400880x4008c
0x400940x40090
0x400980x4009c
0x400a40x400a0
0x400a80x400ac
0x400b40x400b0
0x400b80x400bc
char c;
C-Vorkurs TUM © 2018 O. Bergmann 87
0x400040x40000
0x400080x4000c
0x400140x40010
0x400180x4001c
0x400240x40020
0x400280x4002c
0x400340x40030
0x400380x4003c
0x400440x40040
0x400480x4004c
0x400540x40050
0x400580x4005c
0x400640x40060
0x400680x4006c
0x400740x40070
0x400780x4007c
0x400840x40080
0x400880x4008c
0x400940x40090
0x400980x4009c
0x400a40x400a0
0x400a80x400ac
0x400b40x400b0
0x400b80x400bc
char c[16];
C-Vorkurs TUM © 2018 O. Bergmann 88
int i[20];
0x400040x40000
0x400080x4000c
0x400140x40010
0x400180x4001c
0x400240x40020
0x400280x4002c
0x400340x40030
0x400380x4003c
0x400440x40040
0x400480x4004c
0x400540x40050
0x400580x4005c
0x400640x40060
0x400680x4006c
0x400740x40070
0x400780x4007c
0x400840x40080
0x400880x4008c
0x400940x40090
0x400980x4009c
0x400a40x400a0
0x400a80x400ac
0x400b40x400b0
0x400b80x400bc
C-Vorkurs TUM © 2018 O. Bergmann 89
i[5]=23;
la $t0,i # Load address of i
# = 0x40040
li $t1,5 # Index
sll $t1,$t1,2 # Index*=4, da je 4 Byte
# = 20
add $t0,$t0,$t1 # Offset aufaddieren
# = 0x40054
li $t1,23 # $t1 neu verwenden
sw $t1,($t0) # Store x at address $t0
C-Vorkurs TUM © 2018 O. Bergmann 90
0x400040x40000
0x400080x4000c
0x400140x40010
0x400180x4001c
0x400240x40020
0x400280x4002c
0x400340x40030
0x400380x4003c
0x400440x40040
0x400480x4004c
0x400540x40050
0x400580x4005c
0x400640x40060
0x400680x4006c
0x400740x40070
0x400780x4007c
0x400840x40080
0x400880x4008c
0x400940x40090
0x400980x4009c
0x400a40x400a0
0x400a80x400ac
0x400b40x400b0
0x400b80x400bc
i[5]=23;
23
C-Vorkurs TUM © 2018 O. Bergmann 91
Zusammengesetzter Datentyp
struct element { int a; int b; int c;}
C-Vorkurs TUM © 2018 O. Bergmann 92
0x400040x40000
0x400080x4000c
0x400140x40010
0x400180x4001c
0x400240x40020
0x400280x4002c
0x400340x40030
0x400380x4003c
0x400440x40040
0x400480x4004c
0x400540x40050
0x400580x4005c
0x400640x40060
0x400680x4006c
0x400740x40070
0x400780x4007c
0x400840x40080
0x400880x4008c
0x400940x40090
0x400980x4009c
0x400a40x400a0
0x400a80x400ac
0x400b40x400b0
0x400b80x400bc
struct element a;
C-Vorkurs TUM © 2018 O. Bergmann 93
0x400040x40000
0x400080x4000c
0x400140x40010
0x400180x4001c
0x400240x40020
0x400280x4002c
0x400340x40030
0x400380x4003c
0x400440x40040
0x400480x4004c
0x400540x40050
0x400580x4005c
0x400640x40060
0x400680x4006c
0x400740x40070
0x400780x4007c
0x400840x40080
0x400880x4008c
0x400940x40090
0x400980x4009c
0x400a40x400a0
0x400a80x400ac
0x400b40x400b0
0x400b80x400bc
struct element a[7];
C-Vorkurs TUM © 2018 O. Bergmann 94
Alignment
struct thing { char c; int i;};
Wie lautet der Offset von i?offsetof(struct thing, i)
→ 4
0x40040 c
0x40044 i
0x40048
0x4004c
An Wortgrenze ausgerichtet
Padding
C-Vorkurs TUM © 2018 O. Bergmann 95
Gepackte Strukturen
struct thing { char c; int i;} __attribute__ ((packed));
offsetof(struct thing, i)
→ 1
0x40040 c i
0x40044
0x40048
0x4004c
compilerabhängig(hier: GCC)
C-Vorkurs TUM © 2018 O. Bergmann 96
Dynamische Datenstrukturen● Listen u. ä.● Speicherbedarf ist bei Übersetzung unbekannt● Speicher wird zur Laufzeit dynamisch reserviert
– Adressen sind nicht im Maschinenprogramm enthalten
– Elemente müssen aufeinander verweisen● Adresse einer Datenstruktur ≡ Pointer darauf
C-Vorkurs TUM © 2018 O. Bergmann 97
Pointer
● Wichtiges Konzept in C– In Java versteckt → Umdenken erforderlich → häufige Fehlerquelle
● Pointer „zeigt“ auf ein Objekt im Speicher– Pointer-Variable enthält Speicheradresse, an der das Objekt liegt– Typ des Pointers impliziert Typ des Objekts
● Verwendet u. a. bei dynamischer Speicherverwaltung,direktem Hardwarezugriff
● Nicht unnötig einsetzen für Grunddatentypen und lokale Objekte
C-Vorkurs TUM © 2018 O. Bergmann 98
Pointer: Ein Beispiel
0x40040 i0x40044
0x40048
0x4004c
int i;int *iptr;iptr
iptr = &i;
iptr: 0x40040
Adressoperator
iptr ist vom Typ „Pointer auf int“
C-Vorkurs TUM © 2018 O. Bergmann 99
Operatoren
● Unärer Adressoperator &
– Anwendbar auf Variablenund Arrayelemente
– Nicht auf Werte, Registervariablen
● Dereferenzieren: unärer Operator *
– Umkehrung von &
– Liefert Objekt, auf das ein Pointer zeigt
int i, a[10];unsigned u;int *ptr;
ptr = &i;ptr = &a[10];
ptr = &u;ptr = &3;ptr = &(i+3);Feh
ler!
int i, j = 5;int *ptr = &i;
*ptr = 1; /* i == 1*/ptr = &j;i = *ptr; / *i == 5*/
i = ptr; Fehler!
C-Vorkurs TUM © 2018 O. Bergmann 100
Pointer-Beispieleint i, j = 5;int *ptr; /* "*ptr ist ein int" */char *p, *q; /* "*p und *q sind char" */double *dp, d; /* d ist kein Pointer! */
ptr = &i;
*ptr = 1; /* i ist jetzt 1 */ptr = &j;
i = *ptr; /* i ist jetzt 5 */*ptr += 2; /* j ist jetzt 7 */++*ptr; /* j ist jetzt 8 */(*ptr)++; /* j ist jetzt 9 */
i = ptr; /* falscher Typ */dp = &i; /* falscher Typ */Fehler!
C-Vorkurs TUM © 2018 O. Bergmann 101
Beispiel: Listenelement
struct verpackung {
int laenge;
int breite;
int hoehe;
struct verpackung *next;
};
C-Vorkurs TUM © 2018 O. Bergmann 102
0x400040x40000
0x400080x4000c
0x400140x40010
0x400180x4001c
0x400240x40020
0x400280x4002c
0x400340x40030
0x400380x4003c
0x400440x40040
0x400480x4004c
0x400540x40050
0x400580x4005c
0x400640x40060
0x400680x4006c
0x400740x40070
0x400780x4007c
0x400840x40080
0x400880x4008c
0x400940x40090
0x400980x4009c
0x400a40x400a0
0x400a80x400ac
0x400b40x400b0
0x400b80x400bc
0x40090
0x00000
0x400a0
0x40068
Einfach verkettete Liste
struct verpackung *first;
C-Vorkurs TUM © 2018 O. Bergmann 103
Pointer und Funktionsargumente
● Argumentübergabe in C ist call-by-value● Call-by-reference über Pointer (in Java automatisch)void swap(int *p, int *q) { int temp = *p; *p = *q; *q = temp;}
● Benutzung mit Adressoperatorint x, y, a[10];swap(&x, &y);swap(&a[0], &a[1]);
C-Vorkurs TUM © 2018 O. Bergmann 104
Ergebnisparameter
int getint(int *result) { int c, ok = 0;
*result = 0; c = getc(stdin); if (isdigit(c)) { do { *result = 10 * *result + (c – '0'); c = getc(stdin); } while(c != EOF && isdigit(c)); ok = 1; }
if (c != EOF) { ungetc(c, stdin); }
return ok;}
#include <ctype.h>#include <stdio.h>
...int i;
if (getint(&i)) { /* i is valid... */} else { /* error... */} ...
C-Vorkurs TUM © 2018 O. Bergmann 105
NULL
● Spezieller Wert für Pointer– Zeigt auf „nichts“– Darf nicht dereferenziert werden
● Implizite Typumwandlung 0 → NULL
– Integer 0 darf an Pointer zugewiesen werden
– Pointer kann mit 0 verglichen werden
– (Typ *)0 kann nie valide Adresse sein
● Implizite Typumwandlung in booleschen Ausdrücken, automatische Umtypung
#include <stddef.h>
char *p = NULL;
if (p != 0) ≡ if (p)
C-Vorkurs TUM © 2018 O. Bergmann 106
void *
● Generischer Pointertyp– Cast von Pointer nach void * und zurück ist erlaubt
Typ * → void * → Typ * ist invariant
● void * kann nicht dereferenziert werden
int i;int *ip = &i; /* Pointer auf integer */ char *cp; /* Pointer auf character */ void *vp;
vp = ip; /* erlaubt */vp = cp; /* erlaubt */
ip = vp; /* erlaubt (nicht in C++) */
C-Vorkurs TUM © 2018 O. Bergmann 108
Pointer und Arrays
● Arrays im Prinzip aus Java bekannt● Enger Zusammenhang zwischen Pointer und Array
– Pointer-Zugriff statt Array-Indizierung möglich– Gerade zu Beginn häufige Fehlerquelle
● Pointer können auf Array-Elemente zeigen→ Pointer enthält Adresse von Array-Elementint a[10], *p;p = &a[0]; /* zeigt auf erstes Array-Element */
● Dereferenzierung liefert Inhalt von Array-Element: *p ≡ a[0]
C-Vorkurs TUM © 2018 O. Bergmann 109
0x400040x40000
0x400080x4000c
0x400140x40010
0x400180x4001c
0x400240x40020
0x400280x4002c
0x400340x40030
0x400380x4003c
0x400440x40040
0x400480x4004c
0x400540x40050
0x400580x4005c
0x400640x40060
0x400680x4006c
0x400740x40070
0x400780x4007c
0x400840x40080
0x400880x4008c
0x400940x40090
0x400980x4009c
0x400a40x400a0
0x400a80x400ac
0x400b40x400b0
0x400b80x400bc
Pointer auf Array-Elementint a[10], *p;
p
a[0]
p = &a[0];
0x40040
C-Vorkurs TUM © 2018 O. Bergmann 110
Pointer-Arithmetik● p+1 nächstes Array-Element
● p+i i-tes Element hinter p
● p-i i-tes Element vor pint a[10], *p;p = &a[0];
*p /* liefert a[0] */*(p+1) /* liefert a[1] */*(p+i) /* liefert a[i] */
p += 5;*p /* liefert a[5] */*(p-1) /* liefert a[4] */*(p-i) /* liefert a[5-i] */
i ist typabhängig: Anzahl der Bytes, auf die derPointer zeigt
C-Vorkurs TUM © 2018 O. Bergmann 111
Äquivalente Schreibweisen● Array ist identisch mit Adresse des ersten Elementsp = &a[0] ≡ p = a
● Array/Index-Ausdruck entspricht Pointer/Offset-Ausdruck
Äquivalente Schreibweisen:
a[i] identisch mit *(a+i)&a[i] identisch mit a+i&a[0] identisch mit a
Pointer indizieren:p[i] identisch mit *(p+i)p[-1] identisch mit *(p-1)
C-Vorkurs TUM © 2018 O. Bergmann 112
Unterschiede
● Compiler verwandelt Array-Name in Pointer auf erstes Element– Namen von Array-Variablen
sind konstant
– Kein zusätzlicher Speicher-platz für Pointervariable benötigt
int a[10], *p;
a++; /* Fehler! */a = p; /* Fehler! */
Achtung!sizeof(a)→ 40 sizeof(p)→ 4 bzw. 8sizeof(a)/sizeof(int) Anzahl Elemente in a≡
C-Vorkurs TUM © 2018 O. Bergmann 113
Funktionsargumente
● Umwandlung Array ↔ Pointer● Beispiel: Länge eines Strings (char-Array):int strlen(const char *s) { int n; for (n = 0; *s != '\0'; s++, n++); return n;}
● Funktion arbeitet auf lokaler Kopie des Pointers● Aufruf mit Array oder Pointerstrlen("Hi there!"); /* Konstante */strlen(array); /* char array[80]; */strlen(ptr); /* char *ptr; */
C-Vorkurs TUM © 2018 O. Bergmann 114
Deklaration des formalen Parameters
● Argument wird immer in Pointer umgewandelt
Deklaration als Pointer klarer⇒
int strlen(const char s[]);oder
int strlen(const char *s);
C-Vorkurs TUM © 2018 O. Bergmann 115
Pointer-Vergleich
● Pointer können verglichen werden (<, >, ==, !=)
● Beide Pointer sollten(!) in dasselbe Array zeigen● Sonderfall: Pointer direkt hinter Array OK (&a[size])
● == und != immer definiert
int size = 7;int a[size], *p;
for (p = a; p < a+size; p++) { *p = 0;}
C-Vorkurs TUM © 2018 O. Bergmann 116
Komplizierter...
const int size = 10000;char buf[size];char *bufp = buf;
/* allocate n bytes of memory */void *allocate(int n) { /* check if sufficient storage available */ if (buf + size − bufp >= n) { bufp += n; return bufp − n; /* return start of chunk */ } else { /* no: return NULL pointer */ return NULL; } }
C-Vorkurs TUM © 2018 O. Bergmann 117
Pointer-Differenz
● Pointer dürfen subtrahiert werden (nicht addiert!)
● Ergebnistyp: ptrdiff_t (integer-Typ)
– Anzahl der Elemente zwischen den Pointern
Beispiel: vereinfachtes strlen:int strlen(char *s) { char *p = s; while (*p != '\0') p++; return p - s;}
C-Vorkurs TUM © 2018 O. Bergmann 118
Character-Pointer und Strings● String-Konstante ist ein Character-Array● Automatisch mit '\0' terminiert („Null-Byte“)● Bei Funktionsaufruf: speak("Hello, world");
– Funktion erhält Pointer als Argument● Bei Zuweisung:char *msg;msg = "this is a string";
Pointer
auf e
rstes
Zeiche
n
String w
ird ni
cht k
opier
t!
C-Vorkurs TUM © 2018 O. Bergmann 119
char *buf2 = malloc(sizeof(msg));if (buf2) { strncpy(buf2, msg, 6); ...}free(buf2);
Zeichenketten kopieren
● Entwickler/in ist für Speichermanagement verantwortlichBeispiel: Kopieren einer Zeichenkettechar msg[] = "hello";char buf1[6]; /* 5 chars + Null-byte */strncpy(buf1, msg, strlen(msg) + 1);
Dynamischen Speicherreservieren ...
... und wieder freigeben
besser:char *buf3 = strdup(msg);...free(buf3);
C-Vorkurs TUM © 2018 O. Bergmann 120
Array und Pointer bei Deklaration
● amsg ist konstant, psmg änderbar● amsg enthält Speicherplatz für 6 chars● pmsg enthält Speicherplatz für Adresse● Erste Definition: 6 Bytes (Beispiel)● Zweite Definition: 4/8 Bytes + 6 Bytes
(Beispiel)
char amsg[] = "hello";char *pmsg = "hello";
C-Vorkurs TUM © 2018 O. Bergmann 121
Character-Pointer und Funktionen
● C kennt keine Operatoren für Stringverarbeitung→ Bibliotheksfunktionen (string.h)
● Beispiel: strcpy(s, t) kopiert String t nach s
● Array-Version von strcpy:void strcpy(char *s, char *t) { int i = 0; while ((s[i] = t[i]) != '\0') i++;} Häufiges Idiom:
while (*s++ = *t++);
C-Vorkurs TUM © 2018 O. Bergmann 122
Pointer-Arrays, Pointer auf Pointer
● Pointer-Array-Deklarationchar *names[12];
● Definition mit Initialisierung (für globale Variablen)char *names[] = { "Januar", "Februar", ... };
● Pointer-Array degeneriert zu Pointer auf Pointer in Ausdrücken: char **ptr = names;
Als Schleife:int i;for (i = 0; i < 12; i++) printf("%s\n", names[i]);
Mit Pointern:char **p;for (p = names; p < names+12; p++) printf("%s\n", *p);
C-Vorkurs TUM © 2018 O. Bergmann 123
Argumente der Funktion main()
● argv: Array von Strings● argc: Anzahl der Elemente in argv● argv[0]: Programmname● Rückgabewert: Fehlercode
z. B. echo $?
int main(int argc, char **argv)
C-Vorkurs TUM © 2018 O. Bergmann 124
Beispiel: echo (Shell-Kommando)
/* echo [−n] [arg...] */int main(int argc, char **argv) { int nflag = 0;
if (argc > 1 && argv[1][0] == ’−’ && argv[1][1] == ’n’) { nflag = 1; argc−−; argv++; }
while (−−argc > 0) printf("%s%s", *++argv, (argc > 1 ? " " : "");
if (!nflag) printf("\n");
return 0;}
C-Vorkurs TUM © 2018 O. Bergmann 125
Funktionspointer
● Deklarationint (*p)(int); char *(*q)();
● Zuweisung und Aufrufint add(int a, int b) { return a + b;}
int i, (*f)(int, int);f = &add;i = (*f)(1, 2);void (*strfun)(char *, char *);strfun = &strcpy;
& und * können entfallen:
f = add ≡ f = &addf(1,2) ≡ (*f)(1,2)
C-Vorkurs TUM © 2018 O. Bergmann 126
Typdefinitionen
● Schlüsselwort typedeftypedef int size_t;typedef struct point { double x; double y;} point;
● typedef und Funktionspointertypedef void (*strfunc)(char *, char *);strfunc strfun = strcpy;
C-Vorkurs TUM © 2018 O. Bergmann 127
Beispiel: Quicksort
● base: zu sortierendes Array mit nmemb Elementen
● size: Größe eines Elements● comp: Vergleichsfunktion● Benutzung
void qsort(void *base, size_t nmemb, size_t size, int (*comp)(const void *, const void *));
C-Vorkurs TUM © 2018 O. Bergmann 128
Benutzung von qsort
#include <stdio.h>#include <stdlib.h>#include <string.h>
int cmp(const void *p, const void *q) { return strcmp(*(char **)p, *(char **)q);}
int main(int argc, char **argv) { qsort(++argv, −−argc, sizeof(char *), cmp); while(argc−− > 0) { printf("%s\n", *argv++); } return 0;}
C-Vorkurs TUM © 2018 O. Bergmann 129
Mehrdimensionale Arrays
● Nicht so häufig in C (eher Pointer-Arrays)● Deklaration zweidimensionales Arrayint i [2][10];
– Array mit zwei Elementen– Jedes Element ist ein Array mit zehn ints– Erster Index ist Zeile, zweiter Spalte
→ i[0][0], i[0][1], ... i[0][9], i[1][0], ...
C-Vorkurs TUM © 2018 O. Bergmann 130
Mehrdimensionale Arrays initialisieren
int matrix[2][5] = { { 2, 5, 0, 0, 1 }, { 0, 9, 1, 2, 4 }};
char *days[][7] = { { "Monday", "Tuesday", ... }, { "Montag", "Dienstag", ... }};
Erste Dimensiondarf implizit sein
C-Vorkurs TUM © 2018 O. Bergmann 131
Als Funktionsargumente
● Beispielvoid f(int a[2][10]) { ... }
● Anzahl der Zeilen (erste Dimension) optionalvoid f(int a[][10]) { ... }
● Deklaration als Pointervoid f(int (*a)[10]) { ... }
a ist Pointer aufArray mit zehn ints
Achtung! int *a[10]→ Array mit zehn Pointern
C-Vorkurs TUM © 2018 O. Bergmann 132
Mehrdimensionale Arrays und Pointer
● In Ausdrücken wird Array zu Pointer auf erstes Element (Pointer auf Array)int mat[2][10];int (*p)[10];p = mat; /* oder p = &mat[0]; */
● Durchlaufen einer Zeile mit Pointerint *col;for (col = p[1]; col < p[1] + 10; col++) printf("%s ", *col);
● Frage: was passiert bei p++?
C-Vorkurs TUM © 2018 O. Bergmann 133
Strukturen
● Deklaration (definiert neuen Typ)struct point { int x; int y; };
● Definition von Struktur-Variablenstruct point p;struct point maxpt = { 1024, 768 };
struct rectangle { struct point p1, p2;};
C-Vorkurs TUM © 2018 O. Bergmann 134
Strukturen
● Name in Strukturdeklaration ist optionalstruct { ... } var, *ptr;
● Zugriff auf Komponenten in der Strukturstruct point p; struct rectangle r;p.x = 300; p.y = 500; r.p1.x = p.x;
● Pointer auf Strukturenstruct point origin, *pp;pp = &origin;printf("origin: %d,%d\n", (*pp).x, (*pp).y);
Kürzer: pp->x
C-Vorkurs TUM © 2018 O. Bergmann 135
Arrays von Strukturen
struct key { char *word; int count;};struct key keytab[nkeys];
Deklaration und Initialisierung
struct key keytab[] = { { "break", 0 }, { "case", 0 }, { "char", 0 }, ... { "while", 0 }};
struct key k = { "return", 0};
struct key k = { .count = 0, .word = "return"};
C-Vorkurs TUM © 2018 O. Bergmann 136
Beispiel: Keywords in Eingabe zählen
int main() { int n; char word[MAXWORD];
while (readword(word, MAXWORD)) { if (*word >= ’a’ && *word <= ’z’ && (n = search(word, keytab, nkeys)) >= 0) { keytab[n].count++; } } for (n = 0; n < nkeys; n++) { if (keytab[n].count > 0) printf("%d %s\n", keytab[n].count, keytab[n].word); }}
C-Vorkurs TUM © 2018 O. Bergmann 137
Array-Loop mit Pointer
struct key *p;
for (p = keytab; p < keytab + nkeys; p++) { if (p−>count > 0) { printf("%d %s\n", p−>count, p−>word); }}
C-Vorkurs TUM © 2018 O. Bergmann 138
Tabellengröße berechnen
● automatischint nkeys = sizeof(keytab) / sizeof(key);int nkeys = sizeof keytab / sizeof *keytab;
● Zwei Formen von sizeof:sizeof Objekt sizeof(Typname)
C-Vorkurs TUM © 2018 O. Bergmann 139
Selbst-referenzierende Strukturen
Einfach verkettete Listestruct node { char *word; struct node *next;};
char word[MAXWORD];struct node *list = 0;
while (readword(word, MAXWORD) != EOF) { struct node *p = malloc(sizeof(struct node)); if (p) { p−>word = strdup(word); p−>next = list; list = p; }}
C-Vorkurs TUM © 2018 O. Bergmann 140
Bitfelder● Mehrere Objekte in ein Wort verpacken
– Speichereffizienz– Hardware-Schnittstellen abbilden
● Deklaration als Struktur-Felder– High-order-Bit kann Vorzeichenbit sein (wenn signed)– Bit-Field ohne Typ und Name für Padding
struct employee e;e.is_female = 1;e.num_children = 3;
struct employee { unsigned int is_female : 1; unsigned int is_married : 1; unsigned int num_children : 5; unsigned int age : 6;};
C-Vorkurs TUM © 2018 O. Bergmann 141
Unions
● Zugriff auf Objekte verschiedenen Typs
– Liegen an derselben Speicheradresse
– z. B. wenn Entscheidung über Typ erst zur Laufzeit fällt
union obj { int ival; float fval;} u, *ptr;
u.ival = 5;ptr = &u;i = ptr−>ival;
C-Vorkurs TUM © 2018 O. Bergmann 142
Semantik von Unions
● Ähnlich einer Struktur– Alle Komponenten haben Offset 0– Größe wird durch größtes Feld bestimmt– Alignment passend für alle Typen in union
● Initialisierung
union { int i; float f;} u = { 1234 };
C-Vorkurs TUM © 2018 O. Bergmann 143
„Polymorphie“
enum type_t { FLOAT, STRING };struct object_t { enum type_t type; union { float f; char *s; } u;};struct object_t x, y;x.type = FLOAT; y.type = STRING;x.u.f = 3.141592; y.u.s = "hello";switch (x.type) { case FLOAT: do_float(x.u.f); break; case STRING: do_string(x.u.s); break;}
C-Vorkurs TUM © 2018 O. Bergmann 144
Exkurs: Make
● Wer merkt sich die ganzen Compilerflags?gcc -Wall -Wextra -Isubdir -Llibs ...
● make!– make CFLAGS="-Wall -Wextra" CPPFLAGS=-I...
Makefile:
CFLAGS=-g -O2CPPFLAGS=-Wall -Wextra -IsubdirLDLIBS=-lm
-> make igcc -g -O2 -Wall -Wextra -Isubdir i.c -lm -o i
C-Vorkurs TUM © 2018 O. Bergmann 145
Exkurs: Makefiles
● Make hilft bei getrennter ÜbersetzungMakefile:
CFLAGS=-g -O2CPPFLAGS=-Wall -Wextra -IsubdirLDLIBS=-lm
# i depends on i.o and j.o (from i.c and j.c)i:: i.o j.o
# the first target is the defaultall: i
-> makegcc -g -O2 -Wall -Wextra -Isubdir -c -o i.o i.cgcc -g -O2 -Wall -Wextra -Isubdir -c -o j.o j.cgcc i.o j.o -lm -o i
C-Vorkurs TUM © 2018 O. Bergmann 146
Exkurs: Makefiles-> makegcc -g -O2 -Wall -Wextra -Isubdir -c -o i.o i.cgcc -g -O2 -Wall -Wextra -Isubdir -c -o j.o j.cgcc i.o j.o -lm -o i
-> makemake: `i' is up to date.
-> touch j.c-> makegcc -g -O2 -Wall -Wextra -Isubdir -c -o j.o j.cgcc i.o j.o -lm -o i
Keine Änderungen, keine neueÜbersetzung
j.cc wurde geändertneu übersetzen und alles linken
C-Vorkurs TUM © 2018 O. Bergmann 147
Exkurs: Makefiles● Regeln, Rezepte und Variablen
Makefile:
CFLAGS=-g -O2CPPFLAGS=-Wall -Wextra -IsubdirLDLIBS=-lmCC=clangPACKAGE?=c-kurs
# i depends on i.o and j.o (from i.c and j.c)i:: i.o j.o
# the first target is the defaultall: i
dist: allzip -r $(PACKAGE).zip *.c subdir Makefile
%.pdf: %.texfor f in $$(seq 1 3); do pdflatex $*; done
Lesen und nie wieder ohne make aus dem Haus gehen:http://www.gnu.org/software/make/manual/
C-Vorkurs TUM © 2018 O. Bergmann 148
Exkurs: Makefile mit Bedingung
● Aufrufen mit make GTK_VERSION=3.0Makefile:
CXXFLAGS=-std=c++14CPPFLAGS=-Wall -Wextra -IsubdirLDLIBS=-lmCC=g++
gtkmm_config = $(shell pkg-config gtkmm-$(GTK_VERSION) $1)
ifneq (${GTK_VERSION}, )CPPFLAGS += $(call gtkmm_config,--cflags)LDFLAGS += $(call gtkmm_config,--libs-only-L)LDLIBS += $(call gtkmm_config,--libs-only-l)endif
# ...