C Fortgeschritten - ti.tuwien.ac.at fileC Fortgeschritten Kammerer Präprozessor Allgemeines Makros...
Transcript of C Fortgeschritten - ti.tuwien.ac.at fileC Fortgeschritten Kammerer Präprozessor Allgemeines Makros...
CFortgeschritten
Kammerer
C Fortgeschritten
Roland Kammerer
Institut für Technische InformatikTechnische Universität Wien
12. März 2012
CFortgeschritten
Kammerer
Überblick
1. Präprozessor
2. Komplexe Datentypen
3. Funktionen
4. Modulare Programmierung
CFortgeschritten
Kammerer
PräprozessorAllgemeines
Makros
Allgemeines
I Präprozessor wird vor dem kompilieren aufgerufen
I Erledigt relativ einfache Ersetzungen im Source (casesensitive)
I Source nach dem Präprozessor kann mit gcc -Eeingesehen werden
I MotivationI Früher: Definition von Konstanten. Inline CodeI Heute: Portabilität. Nutzen von Compilerspezifika
Aufgaben des Präprozessors (in zeitlicher Abfolge, nichtvollständig):
I Trigraph → ASCII (z.B. ??) wird zu ])
I Zusammenfassen von durch ’\’ getrennten Zeilen
I Makros ersetzen und Dateien (#include) in den Sourcekopieren
CFortgeschritten
Kammerer
PräprozessorAllgemeines
Makros
Ersetzung von Konstanten
#define ANSWER (42) /* Konstante */
printf("ANSWER: %d\n", ANSWER);
wird zu:
printf("ANSWER: %d\n", (42));
Es findet keine Ersetzung in Stringliteralen statt.
CFortgeschritten
Kammerer
PräprozessorAllgemeines
Makros
Bedingte Ersetzung
#if, #ifdef, #ifndef, #elif, #else, #endif
#ifdef WIN32#include <windows.h>#else#include <unistd.h>#endif
#if DEBUG >= 2printf("debug, debug\n");
#endif
CFortgeschritten
Kammerer
PräprozessorAllgemeines
Makros
Makros
I Komplexe Makros mit Parametern sind möglich
#define NRELEMENTS(a) (sizeof(a) / sizeof(a[0]))
I Makros bergen leider auch viele Gefahren/Seiteneffekte
CFortgeschritten
Kammerer
PräprozessorAllgemeines
Makros
Gefahren
#define DOUBLE(a) a+a
int x = DOUBLE(5) * 3;/* x = 5 + 5 * 3 <=> 5 + (5 * 3) *//* => #define DOUBLE (a) ( (a) + (a) )
#define DOUBLE (a) ( (a) + (a) )
int x = 3;int y = DOUBLE(++x);/* y = ( (++x) + (++x) ) */
CFortgeschritten
Kammerer
DatentypenCasts
void
Structs
Unions
enum
typedef
Alignment
Teil II
Komplexe Datentypen
CFortgeschritten
Kammerer
DatentypenCasts
void
Structs
Unions
enum
typedef
Alignment
Typumwandlung
I Kann implizit passieren
I Kann explizit (cast) passieren
I Syntax: (Zieltyp)Ausdruck;
/* implizit */int i = 5;float f = i;/* erweiternde typumwandlung */
/* explizit */float pi = 3.1415;int i = (int)pi;/* einschraenkende typumwandlung */
CFortgeschritten
Kammerer
DatentypenCasts
void
Structs
Unions
enum
typedef
Alignment
Typumwandlung
I Großer ganzzahliger Typ → kleiner ganzzahliger Typ:Obersten Bits werden abgeschnitten
I Fließkommatyp → kleinerer Typ:I Teil nach dem Komma wird abgeschnitten (falls der Teil vor
dem Komma im kleineren integer Type dargestellt werdenkann).
I Sonst: Verhalten unbestimmt
CFortgeschritten
Kammerer
DatentypenCasts
void
Structs
Unions
enum
typedef
Alignment
voidI void war in frühen C-Versionen nicht vorhanden, mit
ANSI-C eingeführtI Läßt sich am ehesten mit „leerer Datentyp“ beschreiben
Verwendung:I als Ergebnistyp von FunktionenI für leere Parameterlisten von FunktionenI zur Kennzeichnung von Zeiger, denen kein Datentyp
zugeordnet ist
/* void vobject; */ /* nicht zulaessig */void *pv; /* OK: Zeiger auf ein beliebiges Objekt */int *pint; int i;
int foo(void){ /* foo besitzt keine Aufrufparameter */
pv = &i; /* OK */pint = (int *)pv; /* (int *) in C wahlweise,
in C++ erforderlich */return 0;
}
CFortgeschritten
Kammerer
DatentypenCasts
void
Structs
Unions
enum
typedef
Alignment
Structs
I Structs fassen Variablen zu einer logischen Einheitzusammen
I Die Gesamtgröße entspricht prinzipiell der Summe derElemente
I Plus dem Platz der durch das Alignment verbraucht wirdI Zur Bestimmung sizeof verwenden
I Zugriff auf die Elemente erfolgt mit ’.’
struct account {char username[8];char password[8];int uid;
};
struct account user1;struct account user2 = {"john", "doe", 2};
user1.uid = 1;
CFortgeschritten
Kammerer
DatentypenCasts
void
Structs
Unions
enum
typedef
Alignment
Structs
I Tagged Struct:
struct foo {int a;int b;
};struct foo one, two;
I Untagged Struct:
struct {int a;int b;
} one, two;
I Mixed:
struct foo {int a;int b;
} one, two;
CFortgeschritten
Kammerer
DatentypenCasts
void
Structs
Unions
enum
typedef
Alignment
Structs
I Ab C-99 können die Felder eine Struct bei derInitialisierung mit dem Namen angesprochen werden
struct foo {int a;int b;
};
struct foo one = {.b = 23, .a = 42};
CFortgeschritten
Kammerer
DatentypenCasts
void
Structs
Unions
enum
typedef
Alignment
Structs
I Wie auf Variablen sind natürlich auch Pointer auf Structsmöglich
I Dereferenzierung mit ->
struct account {char username[8];char password[8];int uid;
};
struct account user = {"john", "doe", 2};struct account *p = &user;
(*p).uid = 1;p->uid = 1; /* lesbarer */
CFortgeschritten
Kammerer
DatentypenCasts
void
Structs
Unions
enum
typedef
Alignment
Structs#include <stdio.h>#include <stdlib.h>
struct foo{int *a;
};
int main (void){
struct foo x;struct foo *y;
y = &x;
x.a = malloc(sizeof (int));
*y->a = 42;
printf("%d\n", *x.a); /* 42 */printf("%d\n", *y->a); /* 42 */
return 0;}
CFortgeschritten
Kammerer
DatentypenCasts
void
Structs
Unions
enum
typedef
Alignment
Unions
I Elemente einer Union bezeichnen im Unterschied zuStructs den selben Speicherbereich
I Die Gesamtgröße entspricht dem größten Element
I Es kann immer nur ein Element „aktiv“ sein
union zahl {char c_zahl; /* 1 Byte */short s_zahl; /* 1 Byte + 1 Byte */
};
union zahl z;z.s_zahl = 0x23;z.c_zahl = 0x5;
Bei der letzten Zuweisung wird nur die eine Hälfte der Unionverändert. Greift man jetzt wie auf eine s_zahl zu, ist dasErgebnis nicht immer definiert!
CFortgeschritten
Kammerer
DatentypenCasts
void
Structs
Unions
enum
typedef
Alignment
Verschachtelung
I Unions und Structs können nahezu beliebig verschachteltwerden
union vector3d {struct { float x, y, z; } vec1;struct { float alpha, beta, gamma; } vec2;float vec3[3];
};
CFortgeschritten
Kammerer
DatentypenCasts
void
Structs
Unions
enum
typedef
Alignment
Tags
I Häufig wird eine Union von einer Struct umschlossen diezusätzlich eine Variable besitzt die das aktuelle Feld derUnion bezeichnet
struct checkedUnion {int type;union intFloat {
int i;float f;
} intFloat1;};
CFortgeschritten
Kammerer
DatentypenCasts
void
Structs
Unions
enum
typedef
Alignment
enumI Wird verwendet um sprechende Alias-Namen zu vergeben.
I Wenn nicht anders angegeben bekommt das ersteElement den Wert 0
I Wird für ein Element keine Zahl angegeben, bekommt esden Wert des Vorgängers um eins erhöht
I Vorteil gegenüber von #define: Scope
enum [Typname] {Bezeichner [= Wert] {, Bezeichner [= Wert]}};
enum boolean {FALSE = 0, TRUE};enum Farben {rot, gruen, blau};enum Primzahl {
Zwei = 2, Drei, Fuenf = 5, Sieben = 7};
enum boolean mybool;mybool = FALSE;
CFortgeschritten
Kammerer
DatentypenCasts
void
Structs
Unions
enum
typedef
Alignment
enum als Tagsenum types {a_int, a_float};
struct checkedUnion {enum types type;union intFloat{
int i;float f;
} IntFloat1;};
int main(){
struct checkedUnion my_checked_union;
my_checked_union.type = a_float;if (my_checked_union.type == a_int){
my_checked_union.IntFloat1.i = 23;printf("%d\n", my_checked_union.IntFloat1.i);
}return 0; }
CFortgeschritten
Kammerer
DatentypenCasts
void
Structs
Unions
enum
typedef
Alignment
typedef
I Weist einem vorhandenen Typ eine neue Bezeichnung zu
I Besonders geeignet für Structs/Unions
typedef int MyFaNcY_InT;typedef struct {
char username[8];char password[8];int uid;
} user;
MyFaNcY_InT i = 23;user user1 = {"john", "doe", 2};
CFortgeschritten
Kammerer
DatentypenCasts
void
Structs
Unions
enum
typedef
Alignment
Alignment
I Data Alignment: Wie werden Daten im Speicher abgelegt?
I Data Structure Padding: Wie werden die Zwischenräumegefüllt?
Typ Alignment1 (32-bit x86)
char 1-byteshort 2-byteint 4-bytefloat 4-bytedouble 8-byte (win), 4-byte (Linux)long double 4-byte (Linux)pointer 4-byte (Linux)
1für Compiler von Borland, Microsoft und GNU
CFortgeschritten
Kammerer
DatentypenCasts
void
Structs
Unions
enum
typedef
Alignment
Alignment
struct mixed {char data1;short data2;int data3;char data4;
}; /* 8 bytes */
struct mixed { /* nach dem kompilieren */char data1;char padding1[1];short data2;int data3;char data4;char padding2[3]; /* auf groesztes Element */
}; /* 12 bytes */
CFortgeschritten
Kammerer
DatentypenCasts
void
Structs
Unions
enum
typedef
Alignment
Alignment
struct mixed { /* umordnen */int data3;short data2;char data1;char data4;
}; /* 8 bytes */
I Am besten Elemente einer Struct der Größe nachabsteigend anordnen.
I Warum macht das nicht der der Compiler? - Ein Compileroptimiert (ordnet die Elemente um), ein anderer nicht,beide greifen auf eine struct in einem shared memory zu⇒ Problem.
CFortgeschritten
Kammerer
FunktionenWerte alsParameter
Pointer alsParameter
Pointer undconst
Rückgabewerte
inline
Pointer aufFunktionen
Teil III
Funktionen
CFortgeschritten
Kammerer
FunktionenWerte alsParameter
Pointer alsParameter
Pointer undconst
Rückgabewerte
inline
Pointer aufFunktionen
Rückblick
Rückgabetyp Funktionsname(Parameterliste){
Anweisungen}
I Achtung: int foo(); != int foo(void);
I int foo(): foo nimmt eine unbestimmte Anzahl anParametern
I int foo(void): foo darf kein Parameter übergebenwerden
CFortgeschritten
Kammerer
FunktionenWerte alsParameter
Pointer alsParameter
Pointer undconst
Rückgabewerte
inline
Pointer aufFunktionen
Werteparameter
I Werteparameter sind für die Funktion lokal, sie werdennicht verändert
void foo(int a){
a = 23;}
int main(){
int a = 42;foo(a);/* a ist immer noch 42 */return 0;
}
CFortgeschritten
Kammerer
FunktionenWerte alsParameter
Pointer alsParameter
Pointer undconst
Rückgabewerte
inline
Pointer aufFunktionen
Variablenparameter
I Der Funktion wird ein Pointer übergeben (ebenfalls alsWert). Der Inhalt auf den der Pointer zeigt kann geändertwerden.
void foo(int *a){
*a = 23;}
int main(){
int b = 42;foo(&b);/* b hat jetzt den Wert 23 */return 0;
}
CFortgeschritten
Kammerer
FunktionenWerte alsParameter
Pointer alsParameter
Pointer undconst
Rückgabewerte
inline
Pointer aufFunktionen
VariablenparameterI Arrays werden immer als Variablenparameter übergeben.
Dirty Trick: Array in Struct packen um es alsWerteparameter zu übergeben
void foo(int *a){
*a = 23;}
int main(){
int a[] = {1, 2, 3, 4, 5, 6};
foo(a);printf("%d\n", a[0]); /* 23 */foo(&a[3]);printf("%d\n", a[3]); /* 23 */
return 0;}
CFortgeschritten
Kammerer
FunktionenWerte alsParameter
Pointer alsParameter
Pointer undconst
Rückgabewerte
inline
Pointer aufFunktionen
Pointer und const
I const wird verwendet um etwas als nicht veränderbar(konstant/read-only) zu deklarieren
I Sinnvoll bei Funktionsparametern (z.B. strcpy das den srcnicht verändern soll)
char c;char *const cp = &c;/*der Inhalt auf den cp zeigt kann veraendert werdender Pointer kann nicht mehr umgebogen werden */const char *cp;/* der Pointer kann auf eine andere Adresse
gesetzt werden. Der Inhalt auf den derPointer zeigt kann nicht geaendert werden */
I Beide Varianten können gemischt werden (read-only auffixen Speicherbereich). const char * const ptr;
CFortgeschritten
Kammerer
FunktionenWerte alsParameter
Pointer alsParameter
Pointer undconst
Rückgabewerte
inline
Pointer aufFunktionen
Rückgabewerte
I Es können sowohl Werte als auch Pointer zurückgegebenwerden
int mydouble(int a){
return 2*a;}
int main(){
int a;
a = mydouble(5);printf("a ist %d\n", a) /* 10 */
return 0;}
CFortgeschritten
Kammerer
FunktionenWerte alsParameter
Pointer alsParameter
Pointer undconst
Rückgabewerte
inline
Pointer aufFunktionen
Rückgabewerte
char *first_b(char *a) {int i;
for (i = 0; i < strlen(a); ++i) {if (a[i] == ’b’)
return &a[i];}
return NULL;}
int main() {char *string1 = "foobar";char string2[] = "foofoo";char *p;
p = first_b(string1);if (p != NULL)
printf("rest ab b: %s\n", p); /* bar */
return 0;}
CFortgeschritten
Kammerer
FunktionenWerte alsParameter
Pointer alsParameter
Pointer undconst
Rückgabewerte
inline
Pointer aufFunktionen
inline
inline Rückgabetyp Funktionsname(Parameterliste){
Anweisungen}
I Soll laut Standard (ab C-99) so schnell wie möglichausgeführt werden (Hint für den Compiler)
I Implementierung nicht vorgeschrieben. Oft wird derentsprechende Code der Funktion statt dem eigentlichenAufruf in den Code kopiert
I Kann aber auch ignoriert werden
CFortgeschritten
Kammerer
FunktionenWerte alsParameter
Pointer alsParameter
Pointer undconst
Rückgabewerte
inline
Pointer aufFunktionen
FunktionspointerI Man kann nicht nur auf Variablen Pointer zuweisen, sonder
auch auf Funktionen
int (*f) (int, int);
int sub(int a, int b) {return a - b;
}int add(int a, int b) {
return a + b;}
int main() {int ret;
f = sub; /* besser f = &sub */ret = f(42, 23); /* oder (*f)(42, 23); */printf("%d\n", ret); /* 19 */
f = &add;ret = f(42, 23);printf("%d\n", ret); /* 65 */
return 0; }
CFortgeschritten
Kammerer
FunktionenWerte alsParameter
Pointer alsParameter
Pointer undconst
Rückgabewerte
inline
Pointer aufFunktionen
Funktionspointer
#include <stdio.h>
char* (*f) (char *);
char *plusone(char *a){
*a += 1; /* might be dangerous */return &a[0];
}
int main (int argc, char **argv){
char str[] = "hallo";char *p;f = plusone;p = f(str);printf("%s\n", p); /* iallo */return 0;
}
CFortgeschritten
Kammerer
ModulareProgram-mierung*.h Dateien
*.c Dateien
Kompilierung
Teil IV
Modulare Programmierung
CFortgeschritten
Kammerer
ModulareProgram-mierung*.h Dateien
*.c Dateien
KompilierungI Dient der Lesbarkeit, Wiederverwendbarkeit und
Wartbarkeit
I Modul wird in Header (*.h) und Implementierung (*.c)aufgeteilt
CFortgeschritten
Kammerer
ModulareProgram-mierung*.h Dateien
*.c Dateien
Kompilierung
Header Dateien
I Enthalten Prototypen und Konstanten
I Enthalten keine Definitionen von Funktionen(Implementierung geschieht in c-Dateien)
I Werden mit #include <mylib.h> bzw.#include "mylib.h" eingebunden. Ersteres sucht imLibrary-Pfad, zweiteres im lokalen Verzeichnis
/* mylib.h */#ifndef MYLIB_H /* include guard */#define MYLIB_H
#define MYCONST (23)extern int myvar;
int add(int, int);int sub(int, int);#endif /* MYLIB_H */
CFortgeschritten
Kammerer
ModulareProgram-mierung*.h Dateien
*.c Dateien
Kompilierung
Implementierung
I Normale C-Dateien in denen die Funktionenimplementiert werden
I Funktionen die mit static definiert werden, sind nurinnerhalb ihrer C-Datei sichtbar
/* mylib.c */#include "mylib.h"
int add(int a, int b) {return a + b;
}
int sub(int a, int b) {return a - b;
}
CFortgeschritten
Kammerer
ModulareProgram-mierung*.h Dateien
*.c Dateien
Kompilierung
Modul verwenden
I Module/Libraries werden mit #include eingebunden
/* prog.c */#include "mylib.h"
int myvar = 0;
int main(){
int f;
f = add(23, 42);
return 0;}
CFortgeschritten
Kammerer
ModulareProgram-mierung*.h Dateien
*.c Dateien
Kompilierung
Kompilierung
I Projekte die aus mehreren Modulen bestehen werden wiefolgt übersetzt:
$ gcc -c mylib.c # -> mylib.o$ gcc -c prog.c #datei mit main funktion$ gcc -o prog prog.o mylib.o
CFortgeschritten
Kammerer
Material
Material
I C Programming Language - Kernighan & Ritchie
I http://de.wikibooks.org/wiki/C-Programmierung
I AusblickI Traps & Pitfalls
I Lexikalische FallstrickeI Syntaktische FallstrickeI Semantische FallstrickeI Dynamische SpeicherallozierungI Strings und PointerI Makros