(noob-frage) define oder doch typedef...



  • ah danke mit dem Tipp von stdint.h...

    ich persönlich mag uint64_t nicht - stattdessen will ich lieber ulong oder ULONG



  • Hallo,

    so ist das, wenn man als Ent(en)wickler (find ich ja herrlich den Usernamen 😃 ) arbeiten will... Eben noch VCL und C++, nun C. Ich soll ein C-Programm modifizieren und muss nun erstmal durchsteigen, was der Coder / Programmierer da angestellt hat. Dabei bin ich auf einige Makro's in einem Header gestossen, die ich sehr praktisch finde, so Kleinigkeiten wie:

    #define begin {
    #define end   }
    

    Da es in diesem Header noch einige weitere #defines gibt, sind auch Fragen bei mir entstanden...
    Wenn ich richtig informiert bin, werden in obigem Beispiel begin & end zu geschweiften Klammern, dh. ich brauch' im Sourcecode begin & end nicht und kann {} benutzen. Allgemein ist es ja so, dass #define einem Bezeichner einen Ersatztext zuordnet; also:

    #define <Bezeichner> <Ersatztext> bzw. 
    #define <1> <2>
    

    Wenn 1 ein gültiger Bezeichner sein muss, frage ich mich warum Folgendes funktioniert:

    #define UBYTE unsigned char
    

    hier steht doch an 1 der Ersatztext und an 2 der/die Bezeichner??? Oder hab' ich das genau falsch herum verstanden: Dann wäre 1 der neue Bezeichner und 2 der zu ersetzende Text? Da frag' ich mich allerdings was das mit begin & end oben für einen Sinn macht!?

    Auf der Suche nach Antworten bin ich auf diesen Thread hier gestossen. Aber an Stelle von Antworten, kamen noch mehr Fragen auf:

    CStoll schrieb:

    #define definiert eine blinde Textersetzung, typedef einen "neuen" Datentyp - mit letzterem kann der Compiler teilweise besser umgehen.

    was heißt jetzt, der Compiler kann mit typedef besser umgehen? Das ist mir irgendwie zu Allgemein. Und zur "blinden Textersetzung": Ich dachte das wäre gewollt, an Stelle eines neuen Datentyps!?

    Es wäre schön, wenn sich zur richtigen Interpretation von #define jemand äußern könnte und nochmal warum #define schlecht ist (so das es ein Anfänger versteht am Besten).

    MfG



  • Du hast das #define falsch herum betrachtet - #define name irgendwas ersetzt (fast) jedes Vorkommen von 'name' im Quelltext durch 'irgendwas' (und die beiden Makros, die du dort erwähnt hast, ersetzen die Wörter 'begin' und 'end' durch geschweifte Klammern - das ist etwas für Umsteiger, die C unbedingt mit Pascal-artiger Syntax programmieren wollen ;)).

    PS: Ja, der Compiler kann mit typedef's besser umgehen (von den #defines sieht er überhaupt nichts mehr, die werden vorher vom Präprozessor ausgewertet).

    Ein Beispiel (bin mir nicht 100% sicher, ob das klappt):

    //legt einen Arbeitsdatentyp für eine Bibliothek fest
    //#define type double
    typedef double type;
    
    //diese Funktion hat nichts mit der obigen Bibliothek zu tun, sondern wird nur zufällig im selben Programm verwendet
    int irgendwas(int type)
    {
      ...
    }
    

    Mit dem typedef müsste das problemlos klappen - die lokale Variable type überdeckt den gleichnamigen Datentyp. Wenn du den ersetzt durch das #define, sieht der Compiler plötzlich eine Funktion int irgendwas(int double) - und eine Variable darf nicht 'double' heißen.

    (noch schlimmer wird's, wenn du Makros mit Parametern definierst und dann sicherstellen willst, daß sie sich wie inline-Funktionen verhalten)



  • #define NUDELN "Spaghetti " "Maccaroni"
    
    int main()
    { 
    	puts(NUDELN);
    	return 0;
    }
    


  • Ok, Danke für Eure Antworten. Also kann es mit #define zu ungewollten Effekten bzw. schwer auffindbaren Fehlern kommen und mit typedef eher weniger - das macht die Sache etwas klarer.
    Sehe ich das jetzt richtig:

    Mir ist klar, dass ich mit #define <Bezeichner> <Ersatz> einem gültigen Bezeichner einen Alias zuordne, den ich stattdessen im Quelltext verwenden kann (Makro)... Wenn ich jetzt zufällig den Orginal-Bezeichner im Quelltext nutze, wird der dann immer durch den Alias ersetzt!?

    Und hier

    #define UBYTE unsigned char
    

    wird einem Bezeichner den es noch nicht gibt (UBYTE) ein Datentyp zugeordnet!? Wenn also der Bezeichner im Quelltext vom Präprozessor durch den Alias ersetzt wird, heißt das: Ich schreibe UBYTE und der Compiler sieht unsigned char!?
    Daher nutzt "mmmmh lecker" in main() den Bezeichner NUDELN und der Alias (Spaghetti / Maccaroni) wird theoretisch ausgegeben!? (sehr kulinarisches Beispiel - gut, dass ich schon Mittag hatte 🙂 )



  • Kolumbus schrieb:

    Und hier

    #define UBYTE unsigned char
    

    wird einem Bezeichner den es noch nicht gibt (UBYTE) ein Datentyp zugeordnet!?

    Kein Datentyp, einfach eine Zeichenfolge (der Präprozessor kennt keine Datentypen und dergleichen, der kennt nur "Token" (das sind die Grundelemente der Sprache, z.B. '+', 'UBYTE' oder '>>')).

    Wenn also der Bezeichner im Quelltext vom Präprozessor durch den Alias ersetzt wird, heißt das: Ich schreibe UBYTE und der Compiler sieht unsigned char!?

    Ja.

    Daher nutzt "mmmmh lecker" in main() den Bezeichner NUDELN und der Alias (Spaghetti / Maccaroni) wird theoretisch ausgegeben!? (sehr kulinarisches Beispiel - gut, dass ich schon Mittag hatte 🙂 )

    Genau genommen wird erst NUDELN ersetzt durch "Spaghetti " "Maccaroni" , danach werden dies beiden String-Literale zu einem zusammengefasst und der Compiler sieht "Spaghetti Maccaroni".



  • Warum muss man bei Lernprozessen immer eine Tür finden, nur um dann gleich wieder gegen eine Mauer zu rennen? "Token" also, hab ich auch noch nie gehört...
    Demnach wird UBYTE durch #define zu einem "Grundelement der Sprache" (Token) hinter dem sich die Zeichenfolge "unsigned char" verbirgt. Dieses Token ersetzt der Präprozessor durch die Zeichenfolge. Für den Compiler ist das (in diesem Fall) dann allerdings keine schnöde Zeichenfolge mehr, sondern (in diesem Fall) was ganz was Feines, nämlich ein Datentyp! 😃 Ist es etwas dem Compiler unbekanntes, schaut er ins Handbuch (defines).

    #define begin {
    

    funktioniert demzufolge, weil der Präprozessor das "{" stehen lässt und der Compiler ins Handbuch (defines) schaut und feststellt: "jo, das is n begin"!



  • Nicht ganz, aber es geht in die richtige Richtung.

    Zunächst: Ein "Token" ist einfach nur eine Zusammenfassung von Zeichen, die später geschlossen verarbeitet werden können - aus den Zeichen 'U' 'B' 'Y' 'T' 'E' wird das Token "Bezeichner UBYTE", aus zwei aufeinanderfolgenden '>' das Token "Rechtsshift-Operator" etc. Der Präprozessor zerlegt den Porgrammtext in solche Token (und ersetzt dabei einzelne Teile, z.B. den "Bezeichner UBYTE" durch "Typ unsigned char"). Wenn der Compiler später noch etwas findet, was er nicht kennt (oder was an der betrachteten Stelle nicht hinpasst), beschwert er sich bei dir.

    Was das define begin { angeht - der Compiler kennt die geschweifte Klammer, die in C eine Compound-Anweisung eröffnet, also braucht er nirgends nachschauen, was sie bedeutet. Ein Schlüsselwort "begin" kennt er nicht - und würde sich deshalb beschweren, wenn er es finden würde. Also ersetzt der Präprozessor jedes Vorkommen von "begin" durch die geschweifte Klammer und schon kann der Compiler den Quelltext (der ursprünglich in Pascal-artiger Syntax da stand) verstehen.



  • Yeah - ich danke Dir! *WieWildDurchsBüroHüpf* 😃 👍 😃 💡 👍 😃 Ich glaube ich hab's gerafft! Was hätte ich alles lesen müssen, damit ich das kapiert hätte und vor Allem: Wo steht das so? Und nach dieser Erklärung habe ich jetzt nochmal das ganze Projekt durchforstet und tatsächlich einige begin gefunden... aber nur ganz spärlich gestreut!

    Danke nochmal

    MfG



  • Und was sich da noch an Zusatzinfo's findet: begin und { (siehe 2. post von volkard)



  • Hey hab define und typedef jetzt verstanden nur was heißt das nun?

    #define TipcMsgGetNamedInt2Array(a, b, c, d) TipcMsgNextInt2Array ((a),(c),(d))

    Grüße Watercase 😮



  • OK habs verstanden. Somit wird nur an der Stelle eine kürzere Darstellung des Typen vorgenommen.


Anmelden zum Antworten