was bringt #define und #undef



  • hallo ..

    kurze frage. was bringt #define und #undef ?? 😕



  • das sind präprozessor befehle

    du kannst dem präprozessor sagen dass er für das compilen relavante variablen erzeugen soll, die haben absolut keine auswirkungen auf den richtigen runtime quellcode

    mit define erzeugst du bzw belegst solche variablen und mit undef entleerst du sie wieder

    beispiel

    #define windows              // das hier setzt du vorm compilen dann compiliert er nur den windows teil
       #undef windows        // das hier undefiniert windows aber wieder, demnach weis der compiler nicht was er jetzt übersetzen soll
    
    #ifdef windows
    #include <windows.h>
    #define win
    #else
    #include <linux.h>
    #define lin
    #endif
    

    /edit: meistens benutzt man das undef wenn man fremde header dateien includet (windows.h...) und dann etwas umdefineiren will doer ähnliches, da windows ja zum beispiel sehr viele makroconstanten hat



  • #define und #undef sind wie gesagt Präprozessordirektiven.

    Mit #define ist es möglich, Präprozessorsymbole (keine Variablen), auch Makros genannt, zu erzeugen.

    #define blabla     // Symbol "blabla" ist nun definiert.
    #define zahl 2     // Symbol "zahl" ist definiert und entspricht 2.
    

    Wichtig dabei ist, dass wenn nach dem Symbolnamen noch ein Ausdruck steht, der Namen im Programm an allen Stellen durch den Ausdruck dahinter ersetzt wird (rein textuell).

    #undef hebt ein zuvor definiertes Makro wieder auf.

    #define zahl 4
    #undef zahl
    // Zahl ist hier unbekannt.
    

    Eine häufige Anwendung finden Makros als Include-Guards:

    #ifndef HEADER_HPP  // wenn Symbol noch nicht definiert
    #define HEADER_HPP  // Symbol wird definiert, beim nächsten Durchgang wird der Header übersprungen
    ...
    #endif
    

    Makros werden teilweise für konstante Ausdrücke verwendet. Schreibt man

    int i = zahl * 5;   // für zahl wird 2 eingesetzt
    

    , so erhält i den Wert 10.

    Es ist auch möglich, komplexere Ausdrücke zu definieren, die nur im jeweiligen Kontext Sinn machen:

    #define AND &&
    #define OR &&
    
    if (a != b AND !b > c OR d == a)
    

    Man kann damit auch dynamischer arbeiten:

    #define Quadrat(x) x*x
    int i = Quadrat(3);    // i ist 3*3 = 9
    

    Hier sieht man auch bereits ein schönes Problem:

    int j = Quadrat(2+5);  // rein textuell eingesetzt: 2+5*2+5 = 17, nicht wie zu erwarten 49
    

    Um das zu vermeiden, sollte man zusätzlich klammern.

    #define Quadrat(x) ((x)*(x))
    

    Doch das ist nur einer der Nachteile von Makros (zumindest von denen, die mit einem Ausdruck ersetzt werden). Die fehlende Typsicherheit und keine Debugging-Symbole sind weitere. In C++ kann man gerade mit const , (Inline-)Funktionen und Templates meistens das Gleiche erreichen, was ich unbedingt empfehle.



  • Nexus schrieb:

    Doch das ist nur einer der Nachteile von Makros (zumindest von denen, die mit einem Ausdruck ersetzt werden).

    Um noch ein Beispiel zu bringen:

    #define Quadrat1(x) ((x)*(x))
    int Quadrat2( int x ) { return x*x; }
    
    int a = 5;
    int b = Quadrat1( ++a ); // Nach Ersetzung: ((++a)*(++a)), wobei a zwei mal inkrementiert wird, hinterher also 7 ist.
    int b = Quadrat2( ++a ); // a wird nur um eins erhöht, weil der Ausdruck (richtigerweise) nur einmal ausgewertet wird.
    


  • Badestrand schrieb:

    int b = Quadrat1( ++a ); // Nach Ersetzung: ((++a)*(++a)), wobei a zwei mal inkrementiert wird, hinterher also 7 ist.
    

    Ich bin mir nicht einmal sicher, ob das überhaupt definiert ist... Okay, hier spielt es ja keine grosse Rolle, aber mehrfache Inkrementierung einer Variable in einem Ausdruck ist doch undefiniert?



  • Nexus schrieb:

    Badestrand schrieb:

    int b = Quadrat1( ++a ); // Nach Ersetzung: ((++a)*(++a)), wobei a zwei mal inkrementiert wird, hinterher also 7 ist.
    

    Ich bin mir nicht einmal sicher, ob das überhaupt definiert ist... Okay, hier spielt es ja keine grosse Rolle, aber mehrfache Inkrementierung einer Variable in einem Ausdruck ist doch undefiniert?

    Die Reihenfolge ist undefiniert.



  • Deswegen heißt es ja 'Expandierender Makroaufruf'.

    #define Quadrat1(x) ((x)*(x))
    int a = 5;
    int b = Quadrat1( ++a );
    
    //b = 7 * 7 = 49
    

    Der Ausdruck wird eins zu eins übersetzt (Textersetzung) und dann ausgewertet.

    Ein Klassiker.

    Abgesehen von der Umgehung der Typ Kontrolle ist das hier auch noch schwer ersichtlich.


  • Mod

    Nexus schrieb:

    Badestrand schrieb:

    int b = Quadrat1( ++a ); // Nach Ersetzung: ((++a)*(++a)), wobei a zwei mal inkrementiert wird, hinterher also 7 ist.
    

    Ich bin mir nicht einmal sicher, ob das überhaupt definiert ist... Okay, hier spielt es ja keine grosse Rolle, aber mehrfache Inkrementierung einer Variable in einem Ausdruck ist doch undefiniert?

    Ohne Sequenzpunkte dazwischen - wie hier - ist es undefiniert.



  • wobei den fehler mit ++x kann man auch gut umgehen wenn man es einfahc ganz weglässt, denn so bleibt auch alles shcön übersichtlich



  • Skym0sh0 schrieb:

    wobei den fehler mit ++x kann man auch gut umgehen wenn man es einfahc ganz weglässt, denn so bleibt auch alles shcön übersichtlich

    behauptest du gerade man soll ++ und -- generell meiden...?



  • nein

    in for schleifen ist das ok
    aber es gibt ja so spezialisten die die operatoren 5 mal in einer zeile zusammen mit if while und was weis ich verwenden...

    sowas kann lassen und spart sich dann die arbeit auch bei den makros drauf zu achten

    ich benutze das auch gerne, aber dann steht alleine in einer zeile, in der for schleife oder maximal bei irgendwelchen idices von arrays



  • Skym0sh0 schrieb:

    ich benutze das auch gerne, aber dann steht alleine in einer zeile, in der for schleife oder maximal bei irgendwelchen idices von arrays

    foo[++i]
    ist also ok, aber
    foo(++i)
    nicht?



  • Sag' ihm doch einfach, worauf du hinauswillst und gut is 😉

    Nebenbei, eine Variable darf zwischen zwei sequence points nur einmal geändert werden (also im Normalfall nur einmal im ganzen Ausdruck), sonst gibt's undefiniertes Verhalten.



  • Wo wir gerade dabei sind: Was gilt alles als Sequenzpunkt? Komma-Operator, und weiter?



  • Nexus schrieb:

    Wo wir gerade dabei sind: Was gilt alles als Sequenzpunkt? Komma-Operator, und weiter?

    http://www.c-plusplus.net/forum/viewtopic-var-p-is-1570628.html#1570628



  • Skym0sh0 schrieb:

    du kannst dem präprozessor sagen dass er für das compilen relavante variablen erzeugen soll, die haben absolut keine auswirkungen auf den richtigen runtime quellcode

    Wenn dem so wäre, so könnte man sie auch weglassen 😉

    Was du sicher sagen willst: sie tauchen im Quellcode den der Compiler erhält nicht mehr auf, da der Präprozessor diese verarbeitet und das Ergebnis einfügt.



  • -.-

    jeder weis was ich meine...
    jungs ich bin in der 12. klasse und ahbe mathe/physik LK und KEIN deutsch LK

    ich bin kein guter redner und ausdrücken kann ich mich auch nicht so gut

    also hackt nicht so auf mir rum 😢 😢 😢

    @toni: ja genau so 😃
    nein jetzt mal ehrlich ich mag sowas nicht:

    while ( arr[++i] = foo(*(arr+i-1)) != pow(vec[(j++ - ++l)], ++k) );
    

    ok, ist auch kein gutes beispiel, aber sowas is einfahc nur hässlich und unübersichtlich, toll man hat die skills 20 anweisungen in eine zeile zu packen aber wo is der bus mit den leuten die das interresiert?

    aber ma unter uns: jeder solls so amchen wie ers meint
    ich mache öfters mal den hier: a[++i]
    aber sowas mache ich eig nie: a(++i)


  • Administrator

    Skym0sh0 schrieb:

    sowas kann lassen und spart sich dann die arbeit auch bei den makros drauf zu achten

    Ich habe eine bessere Idee. Lieber gleich solche Makros lassen, dann kannst du den Operator nutzen und musst nicht mal dran denken. Für sowas sind Makros einfach nicht gedacht, punkt und aus.

    Und zu dem Zeug mit der Unübersichtlichkeit:
    Aber das hat doch nichts mit dem In- oder Dekrementierungsoperator zu tun. Diese Zeile ist einfach so unübersichtlich. Man sollte Formeln auseinander nehmen und Schrittweise durcharbeiten. Hilft auch unheimlich beim Debuggen und der Compiler kann es so oder so durchoptimieren.

    Skym0sh0 schrieb:

    ich mache öfters mal den hier: a[++i]
    aber sowas mache ich eig nie: a(++i)

    Darf ich fragen wieso? Warum siehst du da einen Unterschied und wie machst du das Untere dann?

    Grüssli



  • ++i;
    a(i);


  • Administrator

    Skym0sh0 schrieb:

    ++i;
    a(i);

    igitt 🙂
    Und wenn du sowas brauchst?
    a(i++);
    Sag mir nicht, dass du dann das hier machst?
    int t = i++;
    a(t);

    Grüssli


Anmelden zum Antworten