Erste Schritte - cm.in.tum.de · C-Vorkurs TUM © 2018 O. Bergmann 3 Ein C-Programm im Emacs $...

141
C-Vorkurs TUM © 2018 O. Bergmann 1 Erste Schritte #include <stdio.h> int main() { printf("Hello world!\n"); } Speichern in hello.c Übersetzen und zusammenbinden cc -o hello hello.c Ausführen ./hello Hello world!

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 3

Ein C-Programm im Emacs$ emacs hallo_welt.c &

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 54

Modularisierung

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 81

Repräsentation vonDaten im Speicher

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 107

Pointer und Arrays

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

# ...