Pointer != NULL : C ? C++



  • Ist das C Style

    if(pointer != NULL)...
    

    Und das C++ Style

    if(pointer)...
    

    Oder ist das egal?



  • 1. Das zweite Beispiel ist C Style
    2. Ja, das ist C++ Style
    3. Alles ist höchst subjektiv und daher sind Aussagen 1 und 2 nicht allgemeingültig



  • Wenn beide pointer raw pointers sind, dann ist beides C Stil. In C++ verlässt man sich auf RAII und smart pointers.

    mfg, NRWsoft



  • NULL ist C-Style. In C++ verwendet man 0, bzw nullptr in C++0x, wobei ich das != 0/nullptr ganz weglassen würde.



  • 314159265358979 schrieb:

    NULL ist C-Style. In C++ verwendet man 0

    In C++ ist NULL als 0 definiert.



  • ääähhh schrieb:

    In C++ ist NULL als 0 definiert.

    Eben.



  • Ein NULL in C ist als "(void *)0" definiert. Wird ein C Include korrekt (ein Systeminclude wie "stdio.h") in eine C++ Datei inkludiert, wird NULL als "0L" redefinert.

    Im Prinzip läuft es auf des gleiche hinaus, da im Memoryrange an der Adresse 0 immer der Inhalt 0 steht. Das ist eine Hardwaredefinition auf x86/x86_64 Systemen und wird auf nicht-Intelsystemen im Betriebssystemkern erzwungen.

    Ein "if (pointer)" funktioniert in C und C++ gleichermaßen. Es wird in beiden Fällen in ein Test auf 0 reduziert, kann man im Assembleroutput auch prima sehen. Ich demonstriere es einfach mal.

    test1.c wurde mit "gcc -O0 -S test1.c" und test2.cpp wurde mit "g++ -O0 -S test2.cpp" übersetzet. Man muss hier die Optimierung abschalten, weil er sonst wegen der Konstante "bla" das if herausoptimiert. 😉

    test1.c

    #include <stdio.h>
    
    int main()
    {
        char *bla = NULL;
    
        if (bla)
            printf("non null\n");
    
        return 0;
    }
    

    test1.s ... nur das main() label

    main:
    .LFB0:
    	.cfi_startproc
    	pushq	%rbp
    	.cfi_def_cfa_offset 16
    	movq	%rsp, %rbp
    	.cfi_offset 6, -16
    	.cfi_def_cfa_register 6
    	subq	$16, %rsp
    	movq	$0, -8(%rbp)
    	cmpq	$0, -8(%rbp)
    	je	.L2
    	movl	$.LC0, %edi
    	call	puts
    

    test2.cpp

    #include <iostream>
    #include <cstdio> // to get NULL
    
    int main()
    {
        char *bla = NULL;
    
        if (bla)
            std::cout << "non null" << std::endl;
    
        return 0;
    }
    

    test2.s ... nur das mein() label

    main:
    .LFB963:
    	.cfi_startproc
    	pushq	%rbp
    	.cfi_def_cfa_offset 16
    	movq	%rsp, %rbp
    	.cfi_offset 6, -16
    	.cfi_def_cfa_register 6
    	subq	$16, %rsp
    	movq	$0, -8(%rbp)
    	cmpq	$0, -8(%rbp)
    	je	.L2
    	movl	$.LC0, %esi
    	movl	$_ZSt4cout, %edi
    	call	_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
    	movl	$_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, %esi
    	movq	%rax, %rdi
    	call	_ZNSolsEPFRSoS_E
    

    Es geht hier in beiden Assemblerquelltexten um die Zeile 11, also das "cmp". Es ist selbst unoptimiert vollkommen identisch. 😉 (um fragen vorzubeugen, ja es ist 64 Bit Code)


  • Global Moderator

    Akiko schrieb:

    Ein NULL in C ist als "(void *)0" definiert.

    Ich bin mir sehr sicher, dass dies in C (eventuell nur C89?) nicht so festgelegt ist, aber ich bin gerade zu faul, den Standard zu durchsuchen. In C++ ist hingegen festgelegt, dass NULL tatsächlich 0 sein muss, weswegen man auch 0 schreiben kann, wenn man NULL meint.

    Der Rest deines Beitrags ist "Beweis" durch Beispiel mit deinem einen Compiler.



  • SeppJ schrieb:

    Der Rest deines Beitrags ist "Beweis" durch Beispiel mit deinem einen Compiler.

    Da haste allerdings recht. Dann korrigiere ich es mal lieber zu einem "es gilt für Unix-artige Systeme mit clang, gcc, Intel und DEC-Conmpiler unter Verwendung der glibc ab 2.3 und der stdc++ v3 und v4". 😃



  • Warum haben sie's eigentlich NULL und nicht ZERO genannt?!



  • Um von "zero" zu unterscheiden. Zero bezeichnet die Zahl 0, null heißt so viel wie "nichtig" oder "nicht-existent".



  • Vielleicht haben sie sich auch von Lisp inspirieren lassen ... null? bzw. die leere Liste '(). Alternative in anderen Sprachen ist nil.



  • 314159265358979 schrieb:

    NULL ist C-Style. In C++ verwendet man 0, bzw nullptr in C++0x, wobei ich das != 0/nullptr ganz weglassen würde.

    Ich verwende in C++ NULL (oder das selbstgebastelte nullptr -Template). Der Code ist klarer als mit 0 , zudem kann man später leichter durch den sicheren C++0x- nullptr ersetzen.


  • Global Moderator

    Ich habe gerade noch mal im Standard gestöbert: NULL ist in C++ garantiert 0 (4.10), in C ist es implementation defined (7.17). Das ändert aber auch nichts an den Antworten in diesem Thread, es dient nur als Bestätigung. Man muss aber vermutlich sehr lange suchen, um eine C-Implementierung mit NULL!=0 zu finden 😉 .



  • ääähhh schrieb:

    314159265358979 schrieb:

    NULL ist C-Style. In C++ verwendet man 0

    In C++ ist NULL als 0 definiert.

    Was nichts an der Tatsache ändert, dass es unleserlich ist und deshalb nicht verwendet werden sollte.



  • 314159265358979 schrieb:

    ääähhh schrieb:

    In C++ ist NULL als 0 definiert.

    Was nichts an der Tatsache ändert, dass es unleserlich ist und deshalb nicht verwendet werden sollte.

    Warum genau ist NULL zur Kennzeichnung von Zeigern unleserlicher als das Integer-Literal 0 ?



  • Nexus schrieb:

    Warum genau ist NULL zur Kennzeichnung von Zeigern unleserlicher als das Integer-Literal 0 ?

    Ich benutze ausschließlich NULL bei Pointern und finde es wesentlich leserlicher, denn NULL signalisiert sofort, dass die Variable ein Pointer ist und es signalisiert sofort, dass der Pointer zum Nullzeiger wird.

    Andererseits ist in der Regel manuelle Ressourcenverwaltung sowieso bei mir ausgeschlossen, daher gibt es auch praktisch keine NULLs mehr.

    mfg, NRWsoft



  • In C ist NULL üblicherweise als ((void*) 0) o. vglb. definiert. In C++ ist diese Definition explizit ausgeschlossen (18.1 (4), Fußnote 180), weil das strengere Typsystem in C++ damit Dinge wie

    non_pod *ptr = NULL;
    

    nicht hergäbe. Explizit vorgeschlagen werden 0 und 0L als Alternativen, und meistens wird auch eine dieser beiden Varianten benutzt. Das Problem, dass sich daraus ergibt (und der Grund, warum NULL in C++ unpopulär ist, obwohl es eigentlich ziemlich gleichgültig ist, ob man NULL oder 0 schreibt), ist, dass NULL verwirrenderweise zwar eine "pointer constant", aber selbst kein Zeiger ist. Zum Beispiel wird

    #include <cstddef>
    #include <iostream>
    
    template<typename T> struct is_pointer_mp     { static bool const val = false; };
    template<typename T> struct is_pointer_mp<T*> { static bool const val = true ; };
    
    template<typename T> bool is_pointer(T) { return is_pointer_mp<T>::val; }
    
    int main() {
      std::cout << (is_pointer(NULL) ? "wahr" : "falsch") << std::endl;
    }
    

    "falsch" ausgeben. Gcc 4.5 warnt hier übrigens:

    test.cc: In Funktion »int main()«:
    test.cc:10:32: Warnung: Übergabe von NULL an Nicht-Zeiger-Argument 1 von »bool is_pointer(T) [with T = long int]«
    

    Schlussendlich kann man es so oder so machen; es ist Geschmackssache. Ein Unterschied in der Programmlogik ergibt sich daraus jedenfalls nicht.



  • Ja, man muss sich bewusst sein, dass NULL ein int und somit nicht typsicher ist. Typsicherheit erreicht man mit dieser Klasse, die aber wieder andere Probleme hat (v.a. im Bezug auf Memberfunktionszeiger).

    In C++0x wird die Problematik mit nullptr ja sauber gelöst.



  • seldon schrieb:

    In C ist NULL üblicherweise als ((void*) 0) o. vglb. definiert. In C++ ist diese Definition explizit ausgeschlossen (18.1 (4), Fußnote 180), weil das strengere Typsystem in C++ damit Dinge wie

    non_pod *ptr = NULL;
    

    nicht hergäbe. Explizit vorgeschlagen werden 0 und 0L als Alternativen, und meistens wird auch eine dieser beiden Varianten benutzt. Das Problem, dass sich daraus ergibt (und der Grund, warum NULL in C++ unpopulär ist, obwohl es eigentlich ziemlich gleichgültig ist, ob man NULL oder 0 schreibt), ist, dass NULL verwirrenderweise zwar eine "pointer constant", aber selbst kein Zeiger ist. Zum Beispiel wird

    #include <cstddef>
    #include <iostream>
    
    template<typename T> struct is_pointer_mp     { static bool const val = false; };
    template<typename T> struct is_pointer_mp<T*> { static bool const val = true ; };
    
    template<typename T> bool is_pointer(T) { return is_pointer_mp<T>::val; }
    
    int main() {
      std::cout << (is_pointer(NULL) ? "wahr" : "falsch") << std::endl;
    }
    

    "falsch" ausgeben.

    Aber 0 bringt da auch nix.