27
Prof. Dr. Nikolaus Wulff Programmieren in C Programmieren in C Operatoren, Variablen und deren Sichtbarkeit

Programmieren in C Operatoren - fh-muenster.de€¦ · sich Java, PHP, C, C# und C++ bei dieser Operationen gleich verhalten sollten (Konjunktiv!) … Prof. Dr. Nikolaus Wulff Programmieren

  • Upload
    others

  • View
    20

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Programmieren in C Operatoren - fh-muenster.de€¦ · sich Java, PHP, C, C# und C++ bei dieser Operationen gleich verhalten sollten (Konjunktiv!) … Prof. Dr. Nikolaus Wulff Programmieren

Prof. Dr. Nikolaus Wulff

Programmieren in CProgrammieren in C

Operatoren, Variablen und deren Sichtbarkeit

Page 2: Programmieren in C Operatoren - fh-muenster.de€¦ · sich Java, PHP, C, C# und C++ bei dieser Operationen gleich verhalten sollten (Konjunktiv!) … Prof. Dr. Nikolaus Wulff Programmieren

Prof. Dr. Nikolaus Wulff Programmieren in C 2

Auswertung von Ausdrücken

Was passiert wenn ein Ausdruck wie z. B.

im Computer abgearbeitet wird?

• Welchen Wert haben x und y nach der Ausführung?

int y,x=2; y = ++x * x++;

• ++x: Der Wert von x wird um 1 erhöht => x=3• *: Multipliziere x mit sich selbst => 9• y= Weise das Ergebnis y zu => y=9• x++: Der Wert von x wird um 1 erhöht =>x=4• Der Ausdruck liefert also x=4, y=9

Page 3: Programmieren in C Operatoren - fh-muenster.de€¦ · sich Java, PHP, C, C# und C++ bei dieser Operationen gleich verhalten sollten (Konjunktiv!) … Prof. Dr. Nikolaus Wulff Programmieren

Prof. Dr. Nikolaus Wulff Programmieren in C 3

Seiteneffekte von Operatoren

Dieses Code-Fragment wurde ~2008 getestet.

int y,x=2; y = ++x * x++;

Bemerkung (2018):

Das Ergebnis x=4,y=9 lies sich 2018 mit dem gcc nicht verifizieren, es lieferte x=4, y=12!

Ein Java Compiler lieferte 2018 nach wie vor x=4, y=9 obwohl sich Java, PHP, C, C# und C++ bei dieser Operationen gleich verhalten sollten (Konjunktiv!) …

Page 4: Programmieren in C Operatoren - fh-muenster.de€¦ · sich Java, PHP, C, C# und C++ bei dieser Operationen gleich verhalten sollten (Konjunktiv!) … Prof. Dr. Nikolaus Wulff Programmieren

Prof. Dr. Nikolaus Wulff Programmieren in C 4

Pedantic & All-Warnings

• Deshalb sollten die compiler settings auf Pedantic und All-Warnings gesetzt werden, um solche Fehler rechtzeitig zu erkennen. Dann verweigert der gcc die Übersetzung:

Page 5: Programmieren in C Operatoren - fh-muenster.de€¦ · sich Java, PHP, C, C# und C++ bei dieser Operationen gleich verhalten sollten (Konjunktiv!) … Prof. Dr. Nikolaus Wulff Programmieren

Prof. Dr. Nikolaus Wulff Programmieren in C 5

Operator Rangfolge

• Das Beispiel führt zur Fragestellung in welcher Reihenfolge die C Operatoren ausgeführt werden.

• Dies darf nicht dem Zufall überlassen sein, sondern muss in der Sprachsyntax festgelegt sein, damit der Compiler eindeutigen Maschinencode generiert.

• C definiert hierzu eine Rangfolge für alle Operatoren, die regelt welche Operatoren und Ausdrücke in welcher Reihenfolge ausgewertet werden.

Page 6: Programmieren in C Operatoren - fh-muenster.de€¦ · sich Java, PHP, C, C# und C++ bei dieser Operationen gleich verhalten sollten (Konjunktiv!) … Prof. Dr. Nikolaus Wulff Programmieren

Prof. Dr. Nikolaus Wulff Programmieren in C 6

Typen von Operatoren

• C kennt unäre, binäre und einen trinären Operator, diese benötigen 1, 2 oder 3 Argumente.

• Unär: <op> <expr1>

– z.B.: -3 , !x , ~y

• Binär: <expr1> <op> <expr

2>

– z.B.: 3 + 5, x & y, i || (j %2)

• Trinär: <expr1> ? <expr

2> : <expr

3>

– z.B.: x<0 ? -x : x

• <expr> kann selber ein Ausdruck sein, der vor der Ausführung der Operation bewertet werden muss.

Page 7: Programmieren in C Operatoren - fh-muenster.de€¦ · sich Java, PHP, C, C# und C++ bei dieser Operationen gleich verhalten sollten (Konjunktiv!) … Prof. Dr. Nikolaus Wulff Programmieren

Prof. Dr. Nikolaus Wulff Programmieren in C 7

Rangfolge der Operatoren

() [] -> . pointer! ~ ++ -- + - * & (type) sizeof* / % arithmetic + - arithmetic<< >> bit-shift< <= >= boolean== != boolean& bit-operation^ bit-operation| bit-operation&& boolean|| boolean?: ternär= += -= *= /= %= &= ^= |= <<= >>=,

Höchster Rang

Niedrigster Rang

• Wie zu erwarten gilt Punkt- vor Strichrechnung.

• Die Vergleiche == und != haben jedoch einen höheren Rang als die Bit Operatoren &,| und ^. Deshalb immer klammern! ...

unär

binär

Page 8: Programmieren in C Operatoren - fh-muenster.de€¦ · sich Java, PHP, C, C# und C++ bei dieser Operationen gleich verhalten sollten (Konjunktiv!) … Prof. Dr. Nikolaus Wulff Programmieren

Prof. Dr. Nikolaus Wulff Programmieren in C 8

Rangeleien

• Bei Ausdrücken mit gleichem Rang schreibt C die Reihenfolge der Bewertung nicht vor.

• In diesem Fall ist nicht klar, ob zuerst f(x) und dann g(x) oder umgekehrt ausgewertet wird.

• Dies sollte im Allgemeinen auch keine Rolle spielen. Anders sieht es aus bei

• sollten hier f oder g den Wert der Variablen x verändern, so ist das Ergebnis y vermutlich falsch...

y = f(x) + g(x)

y = f(&x) + g(&x)

Page 9: Programmieren in C Operatoren - fh-muenster.de€¦ · sich Java, PHP, C, C# und C++ bei dieser Operationen gleich verhalten sollten (Konjunktiv!) … Prof. Dr. Nikolaus Wulff Programmieren

Prof. Dr. Nikolaus Wulff Programmieren in C 9

Pathologische Fälle...

• Die Implementierung der linken Seite verändert die Variable x, so dass die Berechnung

• nicht den „richtigen Wert“

• sondern statt dessen bzw. liefert.

double two(double *x) { *x *=2; return *x;}

double half(double *x) { *x /=2; return *x;}

double two(double *x) { double tmp = *x; return 2*tmp;}

double half(double *x) { double tmp = *x; return tmp/2;}

y = two(&x) + half(&x)

y = 2*x + x/2 = 2.5*x

y = 3*x y = 1.5*x

Page 10: Programmieren in C Operatoren - fh-muenster.de€¦ · sich Java, PHP, C, C# und C++ bei dieser Operationen gleich verhalten sollten (Konjunktiv!) … Prof. Dr. Nikolaus Wulff Programmieren

Prof. Dr. Nikolaus Wulff Programmieren in C 10

C's Systemnähe

• C ermöglicht sehr effizienten, schnellen Code.

• Zeiger und Referenzen sowie die Bit Operatoren erlauben eine maschinennahe Programmierung mit der sich auf jede Speicherzelle des Rechners zugreifen lässt.

• Assembler wird seit C immer seltener.

• Sinnvoll eingesetzt ist dies eine der Stärken von C. Die meisten Hardwaretreiber und Betriebsysteme werden daher in C realisiert.

• Zugleich ist dies jedoch auch in den Händen des ungeübten Programmierers eine Gefahr...

Page 11: Programmieren in C Operatoren - fh-muenster.de€¦ · sich Java, PHP, C, C# und C++ bei dieser Operationen gleich verhalten sollten (Konjunktiv!) … Prof. Dr. Nikolaus Wulff Programmieren

Prof. Dr. Nikolaus Wulff Programmieren in C 11

Noch einmal Stringcopy

void stringcopy(char* src, char* dest) { while(*src) { *dest++ = *src++; }}

void stringcopy(char* src, char* dest) { while( (*dest++ = *src++) ); //nop}

• Unter Ausnutzung der Operatoren Rangfolge kann unsere stringCopy Implementierung

• verkürzt werden zu:

– Zuerst wird die rechte Seite *src ausgewertet,

– das Ergebnis wird der linken Seite *dest zugewiesen,

– dann wird überprüft ob das Ergebnis ungleich 0 ist, falls ja

– werden die Zeiger dest und src inkrementiert ...

Page 12: Programmieren in C Operatoren - fh-muenster.de€¦ · sich Java, PHP, C, C# und C++ bei dieser Operationen gleich verhalten sollten (Konjunktiv!) … Prof. Dr. Nikolaus Wulff Programmieren

Prof. Dr. Nikolaus Wulff Programmieren in C 12

Zeichenketten verschlüsseln

• Einfach lassen sich Zeichenketten mit der XOR Operation verschlüsseln:

• Der XOR Operator ^ sorgt für die Verschlüsselung.

• *++s == '\0' ist die Abbruchbedingung.

• Testlauf: „Hallo World“ coded: „W~ssp?Hpms{“

• Frage wie lässt sich die resultierende Zeichenkette wieder dekodieren?

#define MASK 0x1Fvoid encode(char *s) { do { *s ^= MASK; } while(*++s); }

Page 13: Programmieren in C Operatoren - fh-muenster.de€¦ · sich Java, PHP, C, C# und C++ bei dieser Operationen gleich verhalten sollten (Konjunktiv!) … Prof. Dr. Nikolaus Wulff Programmieren

Prof. Dr. Nikolaus Wulff Programmieren in C 13

Zeichenfelder vergleichen

• Effizient lässt sich das alphabetische Vergleichen zweier Zeichenketten implementieren:

• Die Funktion liefert 0 wenn die Felder s und d identisch sind, ansonsten einen negativen oder positiven Wert, je nach dem ob s alphabetisch kleiner ist als d oder nicht.

int stringcompare(char s[], char d[]) { int i; for(i=0; s[i] == d[i]; i++) { if(s[i] == '\0') return 0; } return s[i] - d[i] ;}

Page 14: Programmieren in C Operatoren - fh-muenster.de€¦ · sich Java, PHP, C, C# und C++ bei dieser Operationen gleich verhalten sollten (Konjunktiv!) … Prof. Dr. Nikolaus Wulff Programmieren

Prof. Dr. Nikolaus Wulff Programmieren in C 14

Zeichenketten Differenz

• Die Methode stringdiff liefert die Differenz der Zeichenketten s und d. D.h. sucht das Vorkommen der ersten Abweichung von s in d.

• Als Resultat liefert sie einen Zeiger char* auf die restliche Zeichenkette aus s zurück.

char* stringdiff(char *s, char *d) { while((*s++ == *d++)) { if(*s == '\0') return s; } return (--s);}

Page 15: Programmieren in C Operatoren - fh-muenster.de€¦ · sich Java, PHP, C, C# und C++ bei dieser Operationen gleich verhalten sollten (Konjunktiv!) … Prof. Dr. Nikolaus Wulff Programmieren

Prof. Dr. Nikolaus Wulff Programmieren in C 15

Falsche StringDiff Variante

• Sehr leicht lässt sich mit Zeigern Chaos anrichten, wie das folgende Beispiel zeigt:

• Das Programm enthält einen schweren Fehler:– Der Aufrufende erwartet eine Zeichenkette erhält

jedoch eine Referenz auf eine lokale Variable &c.

char* stupidDiff(char *s, char *d) { char c; for(; *s; s++, d++) { c = *s; if (c != *d) { return &c; } } return '\0';}

Achtung Bug!Der Compiler generierteine Warnung.

Page 16: Programmieren in C Operatoren - fh-muenster.de€¦ · sich Java, PHP, C, C# und C++ bei dieser Operationen gleich verhalten sollten (Konjunktiv!) … Prof. Dr. Nikolaus Wulff Programmieren

Prof. Dr. Nikolaus Wulff Programmieren in C 16

Lebensdauer von Variablen

Diese letzte Beispiel wirft eine Reihe von Frage auf:

• Welche Zeiger dürfen eigentlich sinnvoller Weise von Methoden zurückgegeben werden?

• Wie lange sind die Variablen gültig?

• Wann und von wem wird der von den Variablen belegte Speicherplatz wieder frei gegeben?

• Wie lange sind Zeiger auf Variablen gültig?

Page 17: Programmieren in C Operatoren - fh-muenster.de€¦ · sich Java, PHP, C, C# und C++ bei dieser Operationen gleich verhalten sollten (Konjunktiv!) … Prof. Dr. Nikolaus Wulff Programmieren

Prof. Dr. Nikolaus Wulff Programmieren in C 17

Variablen

• Ein Programm besteht im Prinzip nur aus Funktionen und Variablen.

• Die Funktionen kapseln das Verhalten.

• Die Variablen den Status des Programms.

• Variablen besitzen eine bestimmte Lebensdauer und eine bestimmte Sichtbarkeit.

• Diese subtileren Eigenschaften kommen erst dann zum Tragen, wenn das Programm aus verschiedenen Funktionen und möglicherweise unterschiedlichen Quelldateien besteht, die zusammen gebunden werden.

Page 18: Programmieren in C Operatoren - fh-muenster.de€¦ · sich Java, PHP, C, C# und C++ bei dieser Operationen gleich verhalten sollten (Konjunktiv!) … Prof. Dr. Nikolaus Wulff Programmieren

Prof. Dr. Nikolaus Wulff Programmieren in C 18

Interne & lokale Variablen

• n: Variable als Parameter

• i, f: lokale Variablen, gültig und sichtbar innerhalb der Funktion factorial.

• es wird nicht f, sondern der Wert von f per return zurückgegeben

• Eine Variable kann als Parameter an eine Funktion übergeben werden oder lokal innerhalb einer Methode definiert werden:

• Ausserhalb der Funktion factorial besitzen i und f keine Gültigkeit und sind dem Compiler unbekannt.

int factorial(int n){ int i, f; f = 1; for(i=2; i<=n; i++) { f *= i; } return f;}

Page 19: Programmieren in C Operatoren - fh-muenster.de€¦ · sich Java, PHP, C, C# und C++ bei dieser Operationen gleich verhalten sollten (Konjunktiv!) … Prof. Dr. Nikolaus Wulff Programmieren

Prof. Dr. Nikolaus Wulff Programmieren in C 19

Sichtbarkeit von Variablen

• Variablen sind i. A. nur lokal innerhalb ihrer sie definierenden Funktion gültig und sichtbar.

• Der selbe Bezeichner kann eine unterschiedliche Bedeutung in verschieden Funktionen haben:

void foo(int x){ int sum; ...}void bar(double sum) { int x;}

• Beide Funktionen foo und bar verwenden zwei Bezeichner: x und sum.

• Diese haben jedoch nichts miteinander gemeinsam, außer (zufällig per Konstruktion) den selben Namen.

• Jede der Variablen ist nur lokal innerhalb der jeweiligen Funktion foo oder bar sichtbar.

Page 20: Programmieren in C Operatoren - fh-muenster.de€¦ · sich Java, PHP, C, C# und C++ bei dieser Operationen gleich verhalten sollten (Konjunktiv!) … Prof. Dr. Nikolaus Wulff Programmieren

Prof. Dr. Nikolaus Wulff Programmieren in C 20

> i=4, j=2

Block scope

• Lokale Variablen sind immer innerhalb eines durch die Klammern „{“ und „}“ markierten Blocks gültig und sichtbar.

• Dies kann auch bedeuten, dass eine Variable innerhalb einer Methode zweimal deklariert wird:

void local() { int i = 1; printf("local i=%d \n", i); { /* block begin */ int j = 2; int i = 4; printf("block i=%d, j=%d \n", i,j); } /* block end */ printf("after block local i=%d \n", i); printf("after block local j=%d \n", j);}

Compile Error

> i=1

> i=1

Page 21: Programmieren in C Operatoren - fh-muenster.de€¦ · sich Java, PHP, C, C# und C++ bei dieser Operationen gleich verhalten sollten (Konjunktiv!) … Prof. Dr. Nikolaus Wulff Programmieren

Prof. Dr. Nikolaus Wulff Programmieren in C 21

Lokale Variablen

• Lokale Variablen sind nur innerhalb der sie definierenden Funktion und Blöcke gültig.

• Sobald der sie einschließende Block verlassen wird verschwindet die Variable, d.h. der Speicherplatz wird automatisch freigegeben.

• Automatische Variablen behalten ihren Wert zwischen zwei Funktionsaufrufen nicht. Sie müssen daher immer wieder neu initialisiert werden.

• Einzige Ausnahme ist, die Variable innerhalb der Methode als static zu definieren, dann bleibt der Wert zwischen zwei Aufrufen erhalten.

Page 22: Programmieren in C Operatoren - fh-muenster.de€¦ · sich Java, PHP, C, C# und C++ bei dieser Operationen gleich verhalten sollten (Konjunktiv!) … Prof. Dr. Nikolaus Wulff Programmieren

Prof. Dr. Nikolaus Wulff Programmieren in C 22

Statische lokale Variablen• Die Variable count behält ihren Wert zwischen

zwei Aufrufen der Funktion remember:

• Im Gegensatz zu den automatischen besitzen die lokalen statischen Variablen ein „Gedächtnis“.

int remember(int n) { static int count; if(n==0) { count=0; } else { count+=n; } return count;}

count ist statisch definiert

Page 23: Programmieren in C Operatoren - fh-muenster.de€¦ · sich Java, PHP, C, C# und C++ bei dieser Operationen gleich verhalten sollten (Konjunktiv!) … Prof. Dr. Nikolaus Wulff Programmieren

Prof. Dr. Nikolaus Wulff Programmieren in C 23

Globale Variablen• Anstatt eine lokale Variable zu verwenden, hätte

count auch als eine globale Variable außerhalb der Funktion definiert werden können:

• Auch diese Variable besitzt ein „Gedächtnis“, das für die gesamte Dauer des Programms gültig ist.

int count=0;

int remember(int n) { if(n==0) { count=0; } else { count+=n; } return count;}

count ist global definiert

Page 24: Programmieren in C Operatoren - fh-muenster.de€¦ · sich Java, PHP, C, C# und C++ bei dieser Operationen gleich verhalten sollten (Konjunktiv!) … Prof. Dr. Nikolaus Wulff Programmieren

Prof. Dr. Nikolaus Wulff Programmieren in C 24

Achtung: Die Funktionen können sich die Werte unter Umständen gegenseitig überschreiben. Dies kann erwünscht oder unerwünscht sein...

Funktionsübergreifende Variablen

• Eine globale Variable ist nicht nur innerhalb einer Funktion sichtbar, sondern ist für die gesamte Programmlaufzeit definiert.

• Somit kann der Wert dieser Variablen von verschiedenen Funktionen gemeinsam genutzt werden.

• Alle Funktionen innerhalb einer *.c Datei „teilen“ sich die globalen Variablen.

Page 25: Programmieren in C Operatoren - fh-muenster.de€¦ · sich Java, PHP, C, C# und C++ bei dieser Operationen gleich verhalten sollten (Konjunktiv!) … Prof. Dr. Nikolaus Wulff Programmieren

Prof. Dr. Nikolaus Wulff Programmieren in C 25

Externe Variablen

• Eine in einer Datei global definierte Variable kann aus einer anderen Quelldatei aus angesprochen und verwendet werden, wenn sie dort als extern definiert ist (geschieht meist in einer *.h Datei):

int count=0;

int remember(int n) { if(n==0) { count=0; } else { count+=n; } return count;}

extern int count;

void dosomething() { if(count==10) { count=-5; } else { ... } }

remember.c something.c

Page 26: Programmieren in C Operatoren - fh-muenster.de€¦ · sich Java, PHP, C, C# und C++ bei dieser Operationen gleich verhalten sollten (Konjunktiv!) … Prof. Dr. Nikolaus Wulff Programmieren

Prof. Dr. Nikolaus Wulff Programmieren in C 26

Sichtbarkeit globaler Variablen

• Globale Variablen können im Programm nur einmal definiert werden. Dies kann zu Problemen führen, wenn solch allgemeine Bezeichner wie i, j, count oder ähnliches verwendet werden, die in vielen Kontexten vorkommen.

• Soll vermieden werden, dass eine globale Variable außerhalb der Quelldatei sichtbar ist, so muss sie als static deklariert werden.

• Sie ist dann global, behält ihr „Gedächtnis“ ist jedoch nur von Funktionen innerhalb der selben Quelldatei aus erreichbar.

Page 27: Programmieren in C Operatoren - fh-muenster.de€¦ · sich Java, PHP, C, C# und C++ bei dieser Operationen gleich verhalten sollten (Konjunktiv!) … Prof. Dr. Nikolaus Wulff Programmieren

Prof. Dr. Nikolaus Wulff Programmieren in C 27

Statische globale Variablen

• Sowohl remember.c als auch something.c besitzen ihre eigene globale count Variable, diese sind jedoch verschieden und nur innerhalb ihrer jeweiligen Quelldatei sichtbar:

static int count=0;

int remember(int n) { if(n==0) { count=0; } else { count+=n; } return count;}

static int count=4;

void dosomething() { if(count==10) ...}void somethingelse() { if(count==3) { ...

remember.c something.c