Jaka jest różnica między NULL, '\0 ' i 0?

W C występują różnice między różnymi wartościami zera -- NULL, NUL i 0.

Wiem, że znak ASCII '0' ocenia się na 48 lub 0x30.

Wskaźnik NULL jest zwykle zdefiniowany jako:

#define NULL 0

Lub

#define NULL (void *)0

Ponadto istnieje znak NUL '\0', który wydaje się oceniać na 0.

Czy są chwile, kiedy te trzy wartości nie mogą być sobie równe?

Czy to też prawda na 64 systemy bitowe?

Author: John Kugelman, 2009-08-18

11 answers

Uwaga: ta odpowiedź dotyczy języka C, a nie c++.


Wskaźniki Null

Stała całkowita literal 0 ma różne znaczenia w zależności od kontekstu, w którym jest używana. We wszystkich przypadkach jest to stała całkowita o wartości 0, jest ona po prostu opisana na różne sposoby.

Jeśli wskaźnik jest porównywany ze stałą literał 0, to jest to sprawdzanie, czy wskaźnik jest wskaźnikiem null. Ta 0 jest następnie określana jako stałą wskaźnika null. Standard C definiuje, że 0 przypisany do typu void * jest zarówno wskaźnikiem null, jak i stałą wskaźnika null.

Dodatkowo, aby ułatwić czytelność, makro NULL znajduje się w pliku nagłówkowym stddef.h. W zależności od kompilatora może być możliwe #undef NULL i Redefiniowanie go do czegoś zwariowanego.

Dlatego oto kilka ważnych sposobów sprawdzania wskaźnika null:

if (pointer == NULL)

NULL jest zdefiniowana w celu porównania równego wskaźnikowi null. Informatyka czy implementacja jest zdefiniowana, czym jest rzeczywista definicja NULL, o ile jest to poprawna stała wskaźnika null.

if (pointer == 0)

0 jest kolejną reprezentacją stałej wskaźnika null.

if (!pointer)

To if stwierdzenie domyślnie sprawdza "nie jest 0", więc odwracamy to, aby oznaczało"jest 0".

Poniżej przedstawiono nieprawidłowe sposoby sprawdzania wskaźnika null:

int mynull = 0;
<some code>
if (pointer == mynull)

Dla kompilatora nie jest to sprawdzanie wskaźnika null, ale sprawdzanie równości dwóch zmiennych. To może działać, jeśli mynull nigdy nie zmieni się w kodzie, a stała optymalizacji kompilatora składa 0 do instrukcji if, ale nie jest to gwarantowane i kompilator musi wygenerować co najmniej jeden komunikat diagnostyczny (ostrzeżenie lub błąd) zgodnie ze standardem C.

Zauważ, że co jest wskaźnikiem null w języku C. Nie ma to znaczenia w podstawowej architekturze. Jeśli bazowa architektura ma wartość wskaźnika null zdefiniowaną jako adres 0xDEADBEEF, to zależy od kompilator do uporządkowania tego bałaganu.

W związku z tym, nawet na tej zabawnej architekturze, następujące sposoby są nadal poprawnymi sposobami sprawdzania wskaźnika null:]}
if (!pointer)
if (pointer == NULL)
if (pointer == 0)

Poniżej przedstawiono nieprawidłowe sposoby sprawdzania wskaźnika null:

#define MYNULL (void *) 0xDEADBEEF
if (pointer == MYNULL)
if (pointer == 0xDEADBEEF)

Ponieważ są one postrzegane przez kompilator jako zwykłe porównania.

Znaki Null

'\0' jest zdefiniowany jako znak null - czyli znak ze wszystkimi bitami ustawionymi na zero. To nie ma nic wspólnego ze wskaźnikami. Jakkolwiek możesz zobacz coś podobnego do tego kodu:

if (!*string_pointer)

Sprawdza, czy wskaźnik Łańcuchowy wskazuje na znak null

if (*string_pointer)

Sprawdza, czy wskaźnik Łańcuchowy wskazuje na inny niż null znak

Nie myl ich ze wskaźnikami null. Tylko dlatego, że reprezentacja bitów jest taka sama, a to pozwala na wygodne krzyżowanie przypadków, tak naprawdę nie są one takie same.

Dodatkowo, '\0' jest (jak wszystkie literały znaków) stałą całkowitą, w tym case Z wartością zero. Tak więc {[21] } jest całkowicie równoważna niezadornowanej 0 stałej całkowitej - jedyną różnicą jest intencja , którą przekazuje ludzkiemu czytelnikowi ("używam tego jako znaku null.").

Referencje

Patrz pytanie 5.3 komp.lang.c FAQ więcej. Zobacz ten plik pdf {[78] } dla standardu C. Zobacz punkty 6.3.2.3, pkt 3.

 364
Author: Andrew Keeton,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-24 08:27:24

Wydaje się, że wiele osób źle rozumie, jakie są różnice między NULL, '\0' i 0. Tak więc, aby wyjaśnić, i w celu uniknięcia powtarzania rzeczy powiedział wcześniej:

Stałe wyrażenie typu {[0] } z wartością 0, lub wyrażenie tego typu, oddane do typu void * jest stałą wskaźnika null , która po przekonwertowaniu do wskaźnika staje się wskaźnikiem null. Standard gwarantuje porównanie z dowolnym wskaźnikiem do dowolnego obiektu lub function .

NULL jest makrem zdefiniowanym jako stała wskaźnika null .

\0 jest konstrukcją używaną do reprezentowania znaku null , używaną do zakończenia łańcucha znaków.

A znak null jest bajtem, który ma wszystkie bity ustawione na 0.

 34
Author: amaterasu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-03-13 07:05:04

Wszystkie trzy definiują znaczenie zera w różnych kontekstach.

  • pointer context - null jest używany i oznacza, że wartość wskaźnika wynosi 0, niezależnie od tego, czy jest to 32bit czy 64bit (jeden przypadek 4 bajty, drugi 8 bajtów zer).
  • string context-znak reprezentujący cyfrę zero ma wartość hex 0x30, podczas gdy znak NUL ma wartość hex 0x00 (używany do kończenia łańcuchów).

Te trzy są zawsze różne, kiedy patrzysz na Pamięć:

NULL - 0x00000000 or 0x00000000'00000000 (32 vs 64 bit)
NUL - 0x00 or 0x0000 (ascii vs 2byte unicode)
'0' - 0x20
Mam nadzieję, że to wszystko wyjaśni.
 14
Author: Nasko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-22 19:27:34

Jeśli null i 0 są równoważne jako stałe wskaźnika null, które należy użyć? w liście FAQ C rozwiązuje również ten problem:

Programiści C muszą zrozumieć, że NULL i {[2] } są wymienne w pointer contexts, and that an uncast 0 jest całkowicie do przyjęcia. Dowolne użycie NULL (w przeciwieństwie do 0) powinno być uważane za delikatne przypomnienie, że w grę wchodzi wskaźnik; Programiści nie powinno zależeć od niego (albo dla własne zrozumienie lub kompilatora) dla odróżnienia wskaźnika 0's from integer 0' S.

Tylko w kontekstach wskaźnikowych, że NULL i 0 są równoważne. NULL powinien nie stosować, gdy inny rodzaj 0 jest wymagane, mimo że może działać, bo robiąc to źle przekaz stylistyczny. (Ponadto ANSI pozwala definicji NULL być ((void *)0), które nie będą działać w wszystko w kontekstach bez wskaźnika.) W szczególnie, nie stosować NULL, gdy na Pożądany jest znak ASCII null (NUL). Podaj własną definicję

#define NUL '\0'
Jeśli musisz.
 6
Author: Sinan Ünür,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-18 22:38:25

Jaka jest różnica między NULL, '\0 ' i 0

"znak null (NUL)" jest najłatwiejszy do wykluczenia. {[2] } jest literalnym znakiem. W C jest zaimplementowany jako int, więc jest taki sam jak 0, które jest INT_TYPE_SIZE. W C++ literał znakowy jest zaimplementowany jako char, czyli 1 bajt. Zwykle różni się to od NULL lub 0.

Następnie, {[6] } jest wartością wskaźnika określającą, że zmienna nie wskazuje na żadną przestrzeń adresową. Pomijając fakt, że jest zazwyczaj zaimplementowany jako zera, musi być w stanie wyrazić pełną przestrzeń adresową architektury. Tak więc na architekturze 32-bitowej NULL (prawdopodobnie) jest 4-bajtowe, a na architekturze 64-bitowej 8-bajtowe. To zależy od implementacji C.

Wreszcie literał {[7] } jest typu int, który ma rozmiar INT_TYPE_SIZE. Domyślna wartość INT_TYPE_SIZE może być różna w zależności od architektury.

Apple napisał (a):

64-bitowy model danych używany przez Mac OS X jest znany jako"LP64". To jest popularnym modelem danych używanym przez inne 64-bitowe systemy uniksowe Sun i SGI, a także 64-bitowy Linux. Model danych LP64 definiuje typy prymitywne w następujący sposób:
  • ints są 32-bitowe
  • długie są 64-bitowe
  • long-Longi są również 64-bitowe
  • wskaźniki są 64-bitowe

Wikipedia 64-bit:

Kompilator VC++ firmy Microsoft wykorzystuje model LLP64.

64-bit data models
Data model short int long  long long pointers Sample operating systems
LLP64      16    32  32    64        64       Microsoft Win64 (X64/IA64)
LP64       16    32  64    64        64       Most Unix and Unix-like systems (Solaris, Linux, etc.)
ILP64      16    64  64    64        64       HAL
SILP64     64    64  64    64        64       ?

Edit : Dodano więcej na charakter dosłowny.

#include <stdio.h>

int main(void) {
    printf("%d", sizeof('\0'));
    return 0;
}

Powyższy kod zwraca 4 w gcc i 1 w g++.

 6
Author: Eugene Yokota,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-19 14:35:01

A one-L NUL, kończy łańcuch.

Dwa-L NULL wskazuje na nic.

I postawię złotego byka

Że nie ma 3-L null.

Jak radzisz sobie z NUL?

 4
Author: EvilTeach,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:33:26

Jeden dobry kawałek, który pomaga mi zaczynać od C (zaczerpnięty z eksperta programowania C przez Linden)

The One' l 'nul and the Two' l ' null

Zapamiętaj ten mały rymowanka, aby przypomnieć poprawną terminologię dla wskaźników i ASCII zero:

The one "l" NUL ends an ASCII string,

The two "l" NULL points to no thing.

Apologies to Ogden Nash, but the three "l" nulll means check your spelling. 
  • znak ASCII o wzorze bitowym zera jest określany jako "NUL".
  • specjalna wartość wskaźnika, która oznacza, że nigdzie nie ma punktów wskaźnika, jest "NULL".
  • te dwa terminy nie są wymienne w to znaczy.
 4
Author: dlmeetei,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2021-01-17 12:12:58

" NUL " nie jest 0, ale odnosi się do znaku ASCII NUL. Przynajmniej tak to widziałem. Wskaźnik null jest często definiowany jako 0, ale zależy to od środowiska, w którym pracujesz, oraz od specyfikacji systemu operacyjnego lub języka, którego używasz.

W ANSI C wskaźnik null jest określony jako wartość całkowita 0. Więc każdy świat, w którym to nie jest prawdą, nie jest zgodny z ANSI C.

 2
Author: peterb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-18 22:16:47

Bajt o wartości 0x00 jest w tabeli ASCII znakiem specjalnym o nazwie NUL lub NULL. W C, ponieważ nie powinieneś osadzać znaków sterujących w kodzie źródłowym, jest to reprezentowane w łańcuchach C z unikalnym 0, tj. \0.

Ale prawdziwe NULL jest , a nie wartością. Jest to brak wartości. W przypadku wskaźnika oznacza to, że wskaźnik nie ma na co wskazywać. W bazie danych oznacza to, że w polu nie ma wartości (co nie jest tym samym, co stwierdzenie, że pole jest puste, 0, lub wypełnione spacjami).

rzeczywista wartość używana przez dany format pliku systemu lub bazy danych do reprezentowania NULL nie musi być 0x00.

 2
Author: richardtallent,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-03-13 09:59:28

NULL nie ma gwarancji, że będzie 0 -- jego dokładna wartość zależy od architektury. Większość głównych architektur definiuje go jako (void*)0.

'\0' zawsze będzie równe 0, ponieważ w ten sposób bajt 0 jest zakodowany w literale znakowym.

Nie pamiętam, czy kompilatory C muszą używać ASCII -- jeśli nie, '0' może nie zawsze być równe 48. Niezależnie od tego, jest mało prawdopodobne, że kiedykolwiek spotkasz system, który używa alternatywnego zestawu znaków, takiego jak EBCDIC, chyba że pracujesz nad very niejasne systemy.

Rozmiary różnych typów będą się różnić w systemach 64-bitowych, ale wartości całkowite będą takie same.


Niektórzy komentatorzy wyrazili wątpliwość, czy NULL jest równe 0, ale nie będzie zero. Oto przykładowy program, wraz z oczekiwanym wynikiem na takim systemie:

#include <stdio.h>

int main () {
    size_t ii;
    int *ptr = NULL;
    unsigned long *null_value = (unsigned long *)&ptr;
    if (NULL == 0) {
        printf ("NULL == 0\n"); }
    printf ("NULL = 0x");
    for (ii = 0; ii < sizeof (ptr); ii++) {
        printf ("%02X", null_value[ii]); }
    printf ("\n");
    return 0;
}

Ten program mógłby wydrukować:

NULL == 0
NULL = 0x00000001
 0
Author: John Millikin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-18 22:59:37

(void*) 0 jest NULL, a '\0 ' reprezentuje koniec łańcucha.

 -2
Author: shinxg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-20 08:41:10