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?
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.
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.
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.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 uncast0
jest całkowicie do przyjęcia. Dowolne użycie NULL (w przeciwieństwie do0
) 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źnika0
's from integer0
' S.Tylko w kontekstach wskaźnikowych, że
NULL
i0
są równoważne.NULL
powinien nie stosować, gdy inny rodzaj0
jest wymagane, mimo że może działać, bo robiąc to źle przekaz stylistyczny. (Ponadto ANSI pozwala definicjiNULL
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.
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++.
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.
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.
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.
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
.
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
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.
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