NULL und 0



  • Soll man 0 statt NULL verwenden? Ein ganz klares jein. Die untypisierte Umwandlung des C Makros in

    ((void *) 0)
    

    nimmt der Übersetzungseinheit Arbeit ab, da (void 😉 praktisch ein Synonym für einen Zeiger auf irgendeinen Typ darstellt. Dieses Prinzip widerstrebt aber C++, weshalb hier NULL mit 0 definiert wird. Beide Ausdrücke sind konform entsprechend der Norm (hey das reimt sich) und beschränken die Philosophie von C bzw. C++ in keinster Weise. Persönlich nutze ich generell NULL. Allein schon wegen zwei Gründen. Der erste ist die Anschaulichkeit des Codes. 0 ist nunmal ein Integer (Ganzzahl), ein Zeiger hingegen eine Art Referenz oder Verweis. Zum zweiten ist nicht auf jedem System 0 gleich NULL, zB Prime 50, Honeywell-Bull Mainframes oder CDC-Cyber 80. Um nur mal einige zu nennen. Code wird somit portabler. Ehrlich gesagt fände ich es sogar noch korrekter für die Abfrage eines NULL gültigen Types eine Makro Abfrage bzw. Template Funktion zu nutzen, also:

    #define IsNull(x) ... // C
    
    template <typename T>
    bool IsNull(T x) ...
    

    Aber ok, man kanns auch übertreiben.
    Generell kann man sagen, jeder sollte es so machen wie er/sie es für richtig hält. Unschlüssigen kann ich aber NULL eher empfehlen.



  • hää das stimmt doch gar nicht (meine ich)!
    NULL != 0;
    macht mal folgendes:

    int var1 = 0;
    int var2 = NULL;

    printf("%d", var1);

    printf("%d", var2);
    printf("%s", var2); // ACHTUNG

    [ Dieser Beitrag wurde am 16.03.2003 um 00:38 Uhr von Peter Piksa editiert. ]



  • Original erstellt von groovemaster2002:
    ist nicht auf jedem System 0 gleich NULL, zB Prime 50, Honeywell-Bull Mainframes oder CDC-Cyber 80. Um nur mal einige zu nennen. Code wird somit portabler.

    Nein. Sowohl 0 als auch NULL (aber auch 0x0, 0l etc pp) sind im Zeigerkontext Nullzeigerkonstanten, die bei der Zuweisung an einen Zeiger jenen in einen Nullzeiger, was lediglich die C-Terminologie für 'ungültiger Zeiger' ist, verwandeln, unabhängig davon, welche Vorstellungen die C-Implementierung von 'ungültigen Segmenten' hat. Ein einfaches 'define NULL 0' ist _immer_ eine gültige Definition von NULL, verwenden tut sie trotzdem fast keine Implementierung, weil dafür die Leute zu schlecht C können:

    printf("%p\n", NULL);
    

    ist zB ein gerne geschriebenes, absolut falsches Konstrukt, das aber zu keinen Absturz führt, wenn man einen 'void*' oder etwas gleichgroßes übergibt. Es lohnt sich wirklich, mal unter DOS programmiert zu haben ...

    Peter Piksa: Wir reden vom Zeigerkontext. Dein Codefetzten ist recht kaputt und kann nichts beweisen.



  • Original erstellt von Daniel E.:
    Dein Codefetzten ist recht kaputt und kann nichts beweisen.

    Wieso nicht? Ich denke es ist schon ein Unterschied wenn einmal "0" und einmal "<null>" ausgegeben wird 😉 :p



  • Das 'Programm' hat undefiniertes Verhalten. Ausgegeben wird hier übrigens ein Compilerfehler. Auch spannend.



  • Original erstellt von Peter Piksa:
    Ich denke es ist schon ein Unterschied wenn einmal "0" und einmal "<null>" ausgegeben wird 😉 :p

    Lies mal die FAQ - da gibts nen Thread darüber.

    Achja: wenn Daniel E. etwas sagt, dann ist das meistens richtig. also hör auf Gurus wie ihn, oder schau einfach in den Headern nach um den Beweis zu finden.

    der code von copy & paster ist aus einer beliebigen header datei kopiert (OK, nicht beliebig, da NULL nicht überall definiert wird)



  • Original erstellt von Shade Of Mine:
    Achja: wenn Daniel E. etwas sagt, dann ist das meistens richtig. also hör auf Gurus wie ihn

    Huch? Ne, ich mache genügend Fehler und bin immer wieder froh, wenn Leute sie finden. Besonders um 1h in der Nacht sollte man mir vielleicht nicht alles glauben ... 😉



  • @Peter Piksa

    hää das stimmt doch gar nicht (meine ich)!
    NULL != 0;

    Bei NULL hätte ich vielleicht eher Nullzeiger schreiben sollen. Das NULL == 0 im normalen C/C++ Kontext ist will ich ja gar nicht bestreiten. Dies ergibt sich allein schon nach der Auflösung des defines. Dafür brauchst du keinen Code mit printf's um das zu beweisen.

    @Daniel E.

    Nein. Sowohl 0 als auch NULL (aber auch 0x0, 0l etc pp) sind im Zeigerkontext Nullzeigerkonstanten, die bei der Zuweisung an einen Zeiger jenen in einen Nullzeiger, was lediglich die C-Terminologie für 'ungültiger Zeiger' ist, verwandeln, unabhängig davon, welche Vorstellungen die C-Implementierung von 'ungültigen Segmenten' hat. Ein einfaches 'define NULL 0' ist _immer_ eine gültige Definition von NULL

    Eben nicht. Welcher *Wert* sich hinter einem Nullzeiger verbirgt ist systemabhängig. Im normalen C/C++ Kontext auf x86 (32/64 Bit) Maschinen mag deine Behauptung zutreffen. Wenn du alleredings ein Programm auf exotische Hardware portierst (siehe mein vorheriger Poll), musst du deinen gesamten Code umschreiben, falls du 0 verwendest hast, da hier ein Nullzeiger jetzt nicht mehr den Wert 0 hat sondern zB 0xB00000000000. Wenn du NULL verwendet hast ist dies kein Problem, da hier lediglich das define angepasst wird. Wie Peter Piksa schon gesagt hat, es ist ein Unterschied ob dann printf "<null>" oder "0xB00000000000" ausgibt.

    printf("%p\n", NULL);
    ist zB ein gerne geschriebenes, absolut falsches Konstrukt, das aber zu keinen Absturz führt, wenn man einen 'void*' oder etwas gleichgroßes übergibt. Es lohnt sich wirklich, mal unter DOS programmiert zu haben ...

    Wieso soll dies ein *absolut falsches Konstrukt* sein?
    Eben wenn du DOS programmiert hast müsstest du ja eigentlich wissen, dass 0 nicht immer ein Nullzeiger ist. Wie du weist gibts unter DOS near und far- Zeiger. Near-Zeiger sind lediglich 16 Bit breit und geben den Segment-Offset an. Wenn also ein solcher Near-Zeiger den Wert 0 hat, muss dies noch lange nicht bedeuten, dass ein Zugriff damit ungültig ist. Solange das Datensegemnt (oder welches Segment auch immer verwendet wird) auf einen gültigen Speicherbereich verweist sind Zugriffe damit OK.

    [ Dieser Beitrag wurde am 16.03.2003 um 14:44 Uhr von groovemaster2002 editiert. ]



  • Original erstellt von groovemaster2002:
    **Welcher *Wert* sich hinter einem Nullzeiger verbirgt ist systemabhängig
    **

    und irrelevant, btw.

    Wenn du alleredings ein Programm auf exotische Hardware portierst (siehe mein vorheriger Poll), musst du deinen gesamten Code umschreiben, falls du 0 verwendest hast, da hier ein Nullzeiger jetzt nicht mehr den Wert 0 hat sondern zB 0xB00000000000.

    Dann würde ich mich schnellstens beim ISO-Komitee beschweren. Die schreiben nämlic in 6.3.2.3p3 (ISO-C) »An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant«. Alles falsch? Krieg' ich dann mein Geld zurück?

    Wenn du NULL verwendet hast ist dies kein Problem, da hier lediglich das define angepasst wird.

    Die Definition von NULL liegt in stdlib.h/cstdlib und auf die hat man keinen Zugriff.

    printf("%p\n", NULL);
    Wieso soll dies ein *absolut falsches Konstrukt* sein?

    Weil zB 'sizeof (int) != sizeof(void*)'. Beim Turbo-C-Compiler hat man je nach Speichermodell NULL auf die passende Größe gesetzt, damit in solchen Situationen (va_args) die Programme nicht abstürzen, obwohl sie falsch sind.

    C beschreibt übrigens keine Computer sondern virtuelle Maschinen. Ein Zeiger in C muss überhaupt nicht auf physikalische Adressen im Speicher zeigen.



  • Original erstellt von groovemaster2002:
    Eben nicht. Welcher *Wert* sich hinter einem Nullzeiger verbirgt ist systemabhängig. Im normalen C/C++ Kontext auf x86 (32/64 Bit) Maschinen mag deine Behauptung zutreffen. Wenn du alleredings ein Programm auf exotische Hardware portierst (siehe mein vorheriger Poll), musst du deinen gesamten Code umschreiben, falls du 0 verwendest hast, da hier ein Nullzeiger jetzt nicht mehr den Wert 0 hat sondern zB 0xB00000000000. Wenn du NULL verwendet hast ist dies kein Problem, da hier lediglich das define angepasst wird. Wie Peter Piksa schon gesagt hat, es ist ein Unterschied ob dann printf "<null>" oder "0xB00000000000" ausgibt.

    darf ich mal den C++ Standard zitieren?

    A null pointer constant is an integral constant expression rvalue of integer type that evaluates to zero.

    Und jetzt erklär mir mal wie 0xB0000 zu 0 werden kann.

    Daniel E. hat recht mit seiner Behauptung - der Standard bestätigt es.

    0 ist im Zeigerkontext etwas anderes als im nicht-Zeiger Kontext. Denn 0 im Zeigerkontext steht für 'NULL-Zeiger'. Ein 'NULL-Zeiger' muss nicht auf die Addresse 0x0000 zeigen (das ist implementation defined).



  • @Daniel E:
    Was hat
    'sizeof (int) != sizeof(void*)'
    mit
    printf("%p\n", NULL);
    zu tun. '%p' zeigt an, dass das Argument ein Zeiger ist und NULL ist nunmal ein Synonym für einen Zeiger, nämlich eine Nullzeiger. Wenn printf nicht weiss wie ein Zeiger aussieht bzw. wie man den aus einer Argumentliste rauskriegt ist das doch nicht die Schuld des Programmierers der printf nutzt. Persönlich halte ich es sogar für unclever, dass Funktionen wie printf va_arg benutzen, da hier Argument an int Grenzen festgesetzt werden.
    Eigentlich dachte ich das *Gurus* soweit denken könnten, dass man auf exotischen Systemen selbstverständlich eine angepasste Version für Funktionen wie printf braucht, nicht umsonst nutzt zB die C stdlib Makros wie _M_ALPHA etc.

    und irrelevant, btw

    OK, ist deine Meinung und die respektier ich *schleim*. Meine Meinung ist das jedenfalls nicht.

    @Shade Of Mine
    wenn du meine Polls mal genau durchgelesen hättest, wäre dir aufgefallen, dass ich nicht behaupte, dass NULL != 0 in Standard C/C++ ist. Oder glaubst du auf exotischer Hardware (naja Windows reicht ja als Bsp. eigentlich auch schon) kommst man mit dem Standard immer ans Ziel?

    0 ist im Zeigerkontext etwas anderes als im nicht-Zeiger Kontext. Denn 0 im Zeigerkontext steht für 'NULL-Zeiger'. Ein 'NULL-Zeiger' muss nicht auf die Addresse 0x0000 zeigen (das ist implementation defined).

    Damit bestätigst du vollkommen meine Ansicht. Die Frage war ja auch ob NULL (bei NULL geh ich jedenfalls davon aus, dass jemand damit einen Nullzeiger beschreibt) und 0 dasselbe sind. Betrachtet man nun 0 im Kontext der Abfrage eines Zeigers sage ich ja, im Kontext des Wertes eines Zeigers nein. Wie ein Nullzeiger ausgewertet wird hängt ja schliesslich vom Compiler ab. Denn auf Maschinensprache-Ebene ist es Wurscht ob du nun einen Zeiger oder Integer hast.

    mov eax, 0x00401000

    Wurde nun hier eax ein Zeiger oder ein Integer zugewiesen?

    Aber ich will nicht zu weit abdriften. Meine damit nur wer 0 verwenden will, bitteschön, der solls auch tun. Dann kann ers bei Abfragen aber auch ganz weglassen.

    if (ptr) ...
    if (!ptr) ...
    

    Ich werde jedenfalls sowohl in C als auch C++ weiterhin NULL verwenden. 😉

    [ Dieser Beitrag wurde am 16.03.2003 um 16:53 Uhr von groovemaster2002 editiert. ]



  • Original erstellt von groovemaster2002:
    Was hat
    'sizeof (int) != sizeof(void
    )'
    mit
    printf("%p\n", NULL);
    zu tun. '%p' zeigt an, dass das Argument ein Zeiger ist
    *

    Aber nicht zur Compilezeit. Nehmen wir mal wieder ein exotisches System, zB ein solches wo Funktionsparameter auf den Stack gelegt werden. Es wird 'etwas' mit sizeof NULL auf den Stack gelegt, und sizeof (void*) gepopt.

    NULL ist nunmal ein Synonym für einen Zeiger, nämlich eine Nullzeiger.

    Nein, das ist der springende Punkt. NULL ist eine Nullzeigerkonstante, bestimmt kein Nullzeiger. Was NULL im nicht-Zeigerkontext macht ist nicht vorgeschrieben.

    Eigentlich dachte ich das *Gurus* soweit denken könnten, dass man auf exotischen Systemen selbstverständlich eine angepasste Version für Funktionen wie printf braucht, nicht umsonst nutzt zB die C stdlib Makros wie _M_ALPHA etc.

    Was willst Du mit deiner 'angepassten Version von printf' machen? Soll sie die Spezifikation von printf erfüllen? Wer ist _M_ALPHA?

    Denn auf Maschinensprache-Ebene ist es Wurscht ob du nun einen Zeiger oder Integer hast.

    Exotische Systeme: Was ist, wenn für Addressoperationen andere Register benutzt werden als für Integer? Was, wenn ein Zeiger größer ist, als ein Integer?
    http://www-info2.informatik.uni-wuerzburg.de/dclc-faq/kap1.html sollte alle Fragen zu Nullzeigern klären.



  • Original erstellt von groovemaster2002:
    **@Shade Of Mine
    wenn du meine Polls mal genau durchgelesen hättest, wäre dir aufgefallen, dass ich nicht behaupte, dass NULL != 0 in Standard C/C++ ist. Oder glaubst du auf exotischer Hardware (naja Windows reicht ja als Bsp. eigentlich auch schon) kommst man mit dem Standard immer ans Ziel?
    **

    Ja das glaube ich. Nicht umsonst hat Standard C++ große einbußen um auch auf exotischer hardware zu rennen (zB threads, gui, sokcets,...)

    Ich hab leider den Standard von eC++ nicht, aber ich denke auch dort gilt in bezug auf 0-zeiger das gleiche.

    Zumindest auf mikrokontrollern ist es so (OK, da verwendet mein Vater C, aber dennoch: 0 bleibt immer 0)

    Damit bestätigst du vollkommen meine Ansicht. Die Frage war ja auch ob NULL (bei NULL geh ich jedenfalls davon aus, dass jemand damit einen Nullzeiger beschreibt) und 0 dasselbe sind. Betrachtet man nun 0 im Kontext der Abfrage eines Zeigers sage ich ja, im Kontext des Wertes eines Zeigers nein. Wie ein Nullzeiger ausgewertet wird hängt ja schliesslich vom Compiler ab. Denn auf Maschinensprache-Ebene ist es Wurscht ob du nun einen Zeiger oder Integer hast.

    mov eax, 0x00401000
    

    Wurde nun hier eax ein Zeiger oder ein Integer zugewiesen?
    auf exotischer hardware kann ein zeiger größer oder kleiner als ein int sein.
    die maschinen ebene ist aber egal für c/c++ programmierer.

    ob er aus einem
    int* p=0;
    ein
    mov xxx, 0x0000
    oder
    mov xxx, 0xgeileaddy
    macht ist mir doch egal.
    auch wenn p nun nicht auf die adresse 0 zeigt, dann ist p dennoch ein 0-zeiger.
    [quote]
    Aber ich will nicht zu weit abdriften. Meine damit nur wer 0 verwenden will, bitteschön, der solls auch tun. Dann kann ers bei Abfragen aber auch ganz weglassen.

    if (ptr) ...
    if (!ptr) ...
    

    Ich werde jedenfalls sowohl in C als auch C++ weiterhin NULL verwenden. 😉

    verwende NULL - niemand will es dir ausreden.
    aber merke:
    NULL liefert immer 0, 0L, 0LL oder ähnliches (immer 0)

    lies den standard wenn du uns nicht glaubst.



  • @Daniel E.
    Wer sizeof(NULL) als printf Argument und im Formatstring "%p" benutzt der ist irgendwie selbst dran Schuld. 😉
    Mit angepasster Version meine ich natürlich, dass man den Source von printf braucht und das ganze nochmal neu compilieren muss für das entsprechende System.

    @Shade Of Mine:

    ob er aus einem
    int* p=0;
    ein
    mov xxx, 0x0000
    oder
    mov xxx, 0xgeileaddy
    macht ist mir doch egal.

    (Wusste garnicht dass es g, i, l und y im Hex-Format gibt. 😃 0xdeadbeef)
    Mag dir zwar egal sein, aber nicht Leuten (wie mir), die teilweise Sequenzen in Assembler programmieren (weiss leider net ob Inline Assembler im C++ Standard erlaubt ist). Da ich mir der Problematik bewusst bin, bin deshalb u.a. gerade dabei sämtliche Routinen direkt in Assembler Module zu packen. Obs was bringt weiss ich nicht, da für andere Systeme solche Sachen meist eh neu programmiert werden müssen. Aber allein um C/C++ strikter von Assembler abzugrenzen denke ich ist dies sinnvoller. Weiss allerdings noch nicht was ich mit inline inline Assembler Funktionen 🙂 machen soll.
    also

    inline int TuIrgendwas()
    {
      __asm {
         ...
      }
    }
    


  • Original erstellt von groovemaster2002:
    **Mit angepasster Version meine ich natürlich, dass man den Source von printf braucht und das ganze nochmal neu compilieren muss für das entsprechende System.
    **

    printf wird wohl überall mehr oder weniger gleich aussehen - vorallem das verhalten ist identisch.

    sicher braucht man für jedes system ein eigenes printf - aber das ist ja der sinn einer library wie die C/C++ Runtime Library: der programmierer muss sich nicht darum kümmern.

    Mag dir zwar egal sein, aber nicht Leuten (wie mir), die teilweise Sequenzen in Assembler programmieren (weiss leider net ob Inline Assembler im C++ Standard erlaubt ist). Da ich mir der Problematik bewusst bin, bin deshalb u.a. gerade dabei sämtliche Routinen direkt in Assembler Module zu packen. Obs was bringt weiss ich nicht, da für andere Systeme solche Sachen meist eh neu programmiert werden müssen.

    damit begibst du dich sowieso in eine compiler und OS abhängigkeit -> insofern hat das nix im C++ Forum zu suchen.

    In C++ braucht man sich nicht um sowas kümmern - und wenn man es doch mal muss, dann ist das sowieso system-spezifisch.



  • Dazu muss man jedoch auch sagen, dass NULL bei Datenbanken nicht das selbe sind wie in C oder C++. Allein schon in den beiden Sprachen gibt es Unterschiede, da das eine nur ein Integer ist und das andere ein richtiger Zeiger auf 0. Wie das jetzt jedoch in Delphi, Java und C# ist weiß ich nicht. Aber in PHP ist null ein Witz der nichts zu sagen hat.

    Meine Erfahrung jedenfalls.



  • @geeky@work
    Musst du wirklich Einträge die sehr alt sind neu aufleben lassen (der letzte Eintrag vor deinem ist von 2003!)?



  • @geeky:
    Aus Versehen auf Seite 53 geklickt und es noch nicht gemerkt?
    Komm mal zurück ins hier und jetzt 😃



  • Ach wie schön, die alte NULL/0 Diskussion wieder 🙂
    Wäre ja auch fad so ein Jahr ohne NULL/0 Diskussion.

    Die einzig IMO vernünftige Antwort ist: in C++ gibt es kein NULL sondern nur 0.
    Wer ein blödes Makro verwenden will soll sich bitte mit PROJEKTNAME_NULLPTR oder ähnlichem selbst eines definieren.



  • geeky wenn du deinen Spamcounter hochtreiben willst, indem du bei toten Threads den Nonsense-Defibrilator ansetzt, solltest du dich vorher einloggen sonst bringt des nix.


Anmelden zum Antworten