Jaka jest różnica między wskaźnikiem wskazującym lokalizację 0x0 a wskaźnikiem ustawionym na NULL?

12

Czy wskaźnik wskazujący na 0x0000 jest taki sam jak wskaźnik ustawiony na NULL? Jeśli wartość NULL jest zdefiniowana w języku C, to w którą lokalizację fizycznie tłumaczy? Czy to to samo co 0x0000. Gdzie mogę znaleźć więcej szczegółów na temat tych pojęć?

Arpith
źródło
1
To pytanie zostało już zadane na przepełnieniu stosu - stackoverflow.com/questions/1296843/… . Myślę, że to dla nas granica, ale w tej chwili jestem gotów dać temu wątpliwości.
ChrisF

Odpowiedzi:

12

Punktem, że większość odpowiedzi tutaj nie odnosi się, przynajmniej nie wprost, jest to, że wskaźnik zerowy jest wartością, która istnieje podczas wykonywania, a stała zerowego wskaźnika jest konstrukcją składniową, która istnieje w kodzie źródłowym C.

Stała wskaźnika zerowego , jak słusznie stwierdza odpowiedź Karlsona, jest albo stałym wyrażeniem całkowitym o wartości 0 ( 0najczęstszym przykładem jest prosty ), albo takim wyrażeniem przypisanym do void*(takim jak (void*)0).

NULLto makro zdefiniowane w <stddef.h>kilku innych standardowych nagłówkach, które rozwija się do zdefiniowanej implementacji stałej wskaźnika zerowego . Rozbudowa jest zazwyczaj 0lub ((void*)0)(potrzebne jest zewnętrzne nawiasach spełniać inne zasady językowe).

Tak dosłowna 0, kiedy używany w kontekście, który wymaga wyrażenia typu wskaźnik, zawsze wynikiem jest null pointer, czyli unikalną wartość wskaźnika, który wskazuje na żaden obiekt. Że nie nie nic o reprezentacji implikuje wskaźnik NULL . Wskaźniki zerowe są bardzo często reprezentowane jako zero-bitowe, ale mogą być reprezentowane jako dowolne. Ale nawet jeśli wskaźnik zerowy jest reprezentowany jako 0xDEADBEEF, 0lub (void*)0nadal jest stałą wskaźnika zerowego .

To odpowiedź na pytanie o stackoverflow Obejmuje to dobrze.

To implikuje, między innymi, że memset()lub calloc(), który może ustawić region pamięci na zero-bitów, niekoniecznie ustawi wskaźniki w tym obszarze na wskaźniki zerowe. Prawdopodobnie zrobią to na większości implementacji, ale język tego nie gwarantuje.

Nie wiem, dlaczego ta kwestia nie jest uważane za duplikat tej jednej , albo jak to miejscowe tutaj.

Keith Thompson
źródło
1
Jednym z moich pomysłów na projekt i ewolucję C jest to, że cyfra zero jest nadal używana jako nieaktualna reprezentacja wskaźnika zerowego. We wczesnych dniach języka (np. Przed pojawieniem się takich rzeczy jak prototypy funkcji) wskaźniki i liczby całkowite były wystarczająco wymienne, aby użycie „0” dla wskaźnika zerowego było proste i „po prostu działałoby”. Kiedy jednak konieczne stało się rozróżnienie między liczbą całkowitą zero a wskaźnikiem zerowym, reprezentacja „0” powinna była zostać przestarzała na rzecz słowa kluczowego lub sekwencji operatora.
supercat
Czy to oznacza, że ​​wskaźnik NULL może faktycznie wskazywać na pewną lokalizację, gdy zostanie mu przypisany NULL w zależności od platformy? Stała wskaźnika zerowego może być konstrukcją składniową, ale co dokładnie dzieje się po uruchomieniu kodu? Załóżmy, że ta konstrukcja składniowa została skompilowana na platformie GNU / Linux. Jaka jest wartość wskaźnika, gdy przypisujemy mu NULL? Czym różni się ten adres od innych adresów?
Arpith,
1
@Arpith: Przypisanie NULLlub dowolna stała wskaźnika zerowego do obiektu wskaźnika ustawia wartość tego obiektu na wskaźnik zerowy . Na poziomie maszyny może to wskazywać na prawidłową porcję pamięci. Dereferencje wskaźnika zerowego mają niezdefiniowane zachowanie; dostęp do części pamięci pod adresem 0x0000000jest prawidłowym zachowaniem, podobnie jak dosłownie wszystko inne. Ten adres różni się od dowolnego innego adresu przez (a) porównanie równe NULLi (b) porównanie nierówne z dowolnym wskaźnikiem do obiektu C. Wskaźnik zerowy to dowolna wartość wskaźnika używana do wskazania, że ​​nie wskazuje na nic.
Keith Thompson,
1
Na poziomie komputera może wskazywać na pewną prawidłową porcję pamięci, ale w większości środowisk C będzie wskazywać na nieprawidłową pamięć, tak że każda próba użycia wskaźnika spowoduje pułapkę sprzętową / błąd / wyjątek. Zwykle odbywa się to tylko na najprostszych platformach sprzętowych --- tych bez obsługi zarządzania pamięcią --- gdzie wskaźnik NULL wskazuje prawidłową lokalizację pamięci.
Solomon Slow
7

Każda platforma może zdefiniować NULL według własnego uznania.

Zgodnie ze standardem C, jeśli przypiszesz zero do wskaźnika, zostanie on przekonwertowany na wartość NULL (dla tej platformy). Jeśli jednak weźmiesz wskaźnik NULL i rzucisz go na int, nie ma gwarancji, że otrzymasz zero na każdej platformie. Faktem jest jednak, że na większości platform będzie to zero.

Informacja o takie rzeczy można znaleźć w katalogu C Language Specification . Jednym ze źródeł, za których wiarygodność nie mogę ręczyć, jest: http://www.winapi.co.kr/pds/doc/ISO-C-FDIS.1999-04.pdf

Mike Nakis
źródło
2
Jeśli zdecydują się zerwać ze standardem, mogą przedefiniować NULL pointer constant. O ile mi wiadomo, nie ma kompilatorów, które to robią.
Karlson,
Czy istnieje jakiś kompilator, który nie implementuje wartości NULL jako 0? I czy NULL ma gwarantowaną wartość fałszywą?
ugoren
Norma ma wartość NULL do oceny fałszywej. Nie wiem, czy istnieje jakiś kompilator (platforma), który nie implementuje wartości NULL jako 0, i poważnie w to wątpię, ale standard tego nie zabrania, więc kto wie.
Mike Nakis,
Jest zamieszanie pomiędzy reprezentacją abstrakcyjnej „Constant wskaźnik NULL” (jak wspomniano w specyfikacji) w pamięci, która może być jak podoba maker platforma i definicji NULLmakra, które ma rozwijać się 0w C ++ i albo 0czy (void *)0w C, ponieważ jest to prawdziwa „stała zerowego wskaźnika”.
Jan Hudec
Chociaż teoretycznie NULL można zdefiniować jako cokolwiek, standard zapewnia jednak, że stała int o wartości 0 przyporządkowanej typowi do wskaźnika da wskaźnik zerowy (ISO 9899: 1999 6.3.2.3/3). Makro NULL pliku stddef.h musi być wskaźnikiem pustym (7.17 / 3), więc kompilator nie wdrożyłby wartości NULL jako 0 lub (void *) 0 byłoby bardzo uciążliwe.
1

Jest zdefiniowany w języku C, ponieważ nie ma jednego niezmiennego adresu maszyny, który byłby mu równy. Gdyby tak było, nie potrzebowalibyśmy od niego abstrakcji! Mimo że na większości platform NULL może ostatecznie zostać zaimplementowany jako 0 jakiegoś typu, to po prostu błędem jest założyć, że jest to uniwersalne, jeśli zależy ci na przenośności.

Kilian Foth
źródło
Takie są standardy dla open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf
Karlson
0

Zgodnie z sekcją dokumentu standardowego C6.3.2.3 :

Wyrażenie stałej liczby całkowitej o wartości 0 lub takie wyrażenie rzutowane na typ void *, nazywane jest stałą wskaźnika zerowego.55) Jeśli stała wskaźnika zerowego jest konwertowana na typ wskaźnika, wynikowy wskaźnik, nazywany wskaźnikiem zerowym, jest gwarantowane porównanie nierówne ze wskaźnikiem do dowolnego obiektu lub funkcji.

Do tej pory nie widziałem kompilatora, który to oderwał.

Karlson
źródło
@ PéterTörök Masz rację, to tyop. :)
Karlson,
1
Tak, ale zauważ, że nie mówi nic o wskaźniku, który faktycznie ma wartość numeryczną 0. Może nie, chociaż na większości platform tak robi.
Jan Hudec