Qual è la differenza tra NULL, '\ 0' e 0?


309

In C, sembrano esserci differenze tra i vari valori di zero - NULL, NULe 0.

So che il carattere ASCII '0'valuta 48o 0x30.

Il NULLpuntatore viene generalmente definito come:

#define NULL 0

O

#define NULL (void *)0

Inoltre, c'è anche il NULpersonaggio '\0'che sembra valutare 0.

Ci sono momenti in cui questi tre valori non possono essere uguali?

Questo vale anche per i sistemi a 64 bit?


1
Vedi stackoverflow.com/questions/176989/… per qualche informazione in più sulle differenze tra 0 e NULL.
David Rodríguez - dribeas,

7
L'identificatore NULnon esiste nel linguaggio o nella libreria standard C (o in C ++ per quanto ne so). Il carattere null viene talvolta chiamato NUL, ma in genere C o C ++ viene di solito indicato come '\0'.
Keith Thompson,

Risposte:


351

Nota: questa risposta si applica al linguaggio C, non a C ++.


Puntatori null

La costante intera letterale 0ha significati diversi a seconda del contesto in cui viene utilizzata. In tutti i casi, è ancora una costante intera con il valore 0, è appena descritta in diversi modi.

Se un puntatore viene confrontato con il costante letterale 0, questo è un controllo per vedere se il puntatore è un puntatore nullo. Questa 0viene quindi definita costante del puntatore null. Lo standard C definisce che il 0cast per il tipo void *è sia un puntatore null che una costante puntatore null.

Inoltre, per facilitare la leggibilità, la macro NULLviene fornita nel file di intestazione stddef.h. A seconda del compilatore, potrebbe essere possibile #undef NULLe ridefinirlo in qualcosa di strano.

Pertanto, ecco alcuni modi validi per verificare la presenza di un puntatore null:

if (pointer == NULL)

NULLè definito per confrontare uguale a un puntatore nullo. È l'implementazione definita quale sia la definizione effettiva NULL, purché sia ​​una costante puntatore null valida.

if (pointer == 0)

0 è un'altra rappresentazione della costante puntatore null.

if (!pointer)

Questa ifaffermazione controlla implicitamente "non è 0", quindi invertiamo che significa "è 0".

Di seguito sono riportati i metodi NON VALIDI per verificare la presenza di un puntatore null:

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

Per il compilatore questo non è un controllo per un puntatore nullo, ma un controllo di uguaglianza su due variabili. Questo potrebbe funzionare se mynull non cambia mai nel codice e le ottimizzazioni del compilatore costano lo 0 nell'istruzione if, ma ciò non è garantito e il compilatore deve produrre almeno un messaggio diagnostico (avviso o errore) secondo lo standard C.

Si noti che cos'è un puntatore null nel linguaggio C. Non importa sull'architettura sottostante. Se l'architettura sottostante ha un valore di puntatore nullo definito come indirizzo 0xDEADBEEF, spetta al compilatore ordinare questo pasticcio.

Pertanto, anche su questa architettura divertente, i seguenti modi sono ancora validi per verificare la presenza di un puntatore null:

if (!pointer)
if (pointer == NULL)
if (pointer == 0)

Di seguito sono riportati i metodi NON VALIDI per verificare la presenza di un puntatore null:

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

poiché questi sono visti da un compilatore come normali confronti.

Personaggi Null

'\0'è definito come un carattere nullo, ovvero un carattere con tutti i bit impostati su zero. Questo non ha nulla a che fare con i puntatori. Tuttavia potresti vedere qualcosa di simile a questo codice:

if (!*string_pointer)

controlla se il puntatore di stringa punta a un carattere null

if (*string_pointer)

controlla se il puntatore di stringa punta a un carattere non nullo

Non confonderli con puntatori null. Solo perché la rappresentazione dei bit è la stessa, e questo consente alcuni comodi casi incrociati, non sono proprio la stessa cosa.

Inoltre, '\0'è (come tutti i letterali dei caratteri) una costante intera, in questo caso con il valore zero. Quindi '\0'è completamente equivalente a una 0costante intera senza ornamenti - l'unica differenza è nell'intento che trasmette a un lettore umano ("Sto usando questo come carattere nullo").

Riferimenti

Vedi la domanda 5.3 delle FAQ di comp.lang.c per ulteriori informazioni. Vedi questo pdf per lo standard C. Consulta le sezioni 6.3.2.3 Puntatori, paragrafo 3.


3
Grazie per aver indicato l'elenco delle FAQ. Tuttavia, vedi anche c-faq.com/null/nullor0.html
Sinan Ünür

4
No, non comparerai ptrcon all-bit-zero . Questo non è un memcmp, ma questo è un confronto usando un operatore incorporato. Un lato è una costante di puntatore null '\0'e l'altro lato è un puntatore. Così come con le altre due versioni con NULLe 0. Quei tre fanno le stesse cose.
Johannes Schaub - litb

6
Stai prendendo l'operatore di confronto integrato come una cosa che confronta le stringhe di bit. Ma non è quello che è. Confronta due valori, che sono concetti astratti. Quindi un puntatore nullo che internamente viene rappresentato come 0xDEADBEEFè ancora un puntatore nullo, non importa quale sia il suo aspetto stringa di bit piace, e sarà ancora confrontare pari a NULL, 0, \0e tutte le altre forme costanti puntatore nullo.
Johannes Schaub - litb

2
Hai un buon punto sull'operatore di confronto. Ho ripassato il C99. Dice "Un'espressione di una costante intera con il valore 0, o tale espressione cast per digitare void *, è chiamata costante di puntatore null". Dice anche che un carattere letterale è un'espressione costante intera. Quindi, per la proprietà transitiva hai ragione ptr == '\0'.
Andrew Keeton,

2
".... potrebbe essere possibile #undef NULL e ridefinirlo in qualcosa di stravagante. Chiunque lo faccia merita di essere ucciso." questo mio buon signore mi ha fatto ridere ad alta voce ...
oggiemc

34

Sembra che un numero di persone fraintenda quali sono le differenze tra NULL, '\ 0' e 0. Quindi, per spiegare, e nel tentativo di evitare di ripetere le cose detto in precedenza:

Un'espressione costante di tipo intcon il valore 0, o un'espressione di questo tipo, trasmessa al tipo void *è una costante puntatore null , che se convertita in un puntatore diventa un puntatore null . Lo standard garantisce che non sia uguale a nessun puntatore a nessun oggetto o funzione .

NULLè una macro, definita come costante puntatore null .

\0è una costruzione utilizzata per rappresentare il carattere null , utilizzata per terminare una stringa.

Un carattere null è un byte che ha tutti i suoi bit impostati su 0.


14

Tutti e tre definiscono il significato di zero in diversi contesti.

  • contesto del puntatore: viene utilizzato NULL e indica che il valore del puntatore è 0, indipendentemente dal fatto che sia 32 bit o 64 bit (un caso 4 byte e altri 8 byte di zero).
  • contesto stringa: il carattere che rappresenta la cifra zero ha un valore esadecimale di 0x30, mentre il carattere NUL ha un valore esadecimale di 0x00 (utilizzato per terminare le stringhe).

Questi tre sono sempre diversi quando guardi la memoria:

NULL - 0x00000000 or 0x00000000'00000000 (32 vs 64 bit)
NUL - 0x00 or 0x0000 (ascii vs 2byte unicode)
'0' - 0x20

Spero che questo lo chiarisca.


8
Nasko: valuta sizeof('\0')e lasciati sorprendere.
Caf

3
@Nasko: sono rimasto davvero sorpreso: con gcc, in C: sizeof ('\ 0') == sizeof ('a') == 4, mentre con g ++, in C ++: sizeof ('\ 0') == sizeof ('a') == 1
David Rodríguez - dribeas,

1
@Nasko: Dallo standard C (draft, n1124): 'Una costante di carattere intero ha tipo int', quindi '\ 0' è in realtà di tipo int in C, e quindi sizeof ('\ 0') è 4 nella mia architettura (Linux, 32 bit)
David Rodríguez - dribeas,

@dribeas - Non lo stavo descrivendo come costante, ma piuttosto come vedresti come parte della stringa. Avrei sicuramente potuto renderlo esplicito. Grazie
Nasko il

@ DavidRodríguez-dribeas Annulla modifica "Valore ASCII" 0 "corretto su 0x20 (dic 32)"
chux - Ripristina Monica

6

Se NULL e 0 sono equivalenti come costanti puntatore null, quale devo usare? nell'elenco C FAQ risolve anche questo problema:

Programmatori C devono capire che NULLe 0sono intercambiabili in contesti puntatore, e che un non convertito 0 è perfettamente accettabile. Qualsiasi utilizzo di NULL (al contrario di 0) dovrebbe essere considerato un gentile promemoria del coinvolgimento di un puntatore; i programmatori non dovrebbero dipendere da esso (né per la propria comprensione né per quello del compilatore) per distinguere i puntatori 0da quelli interi 0.

È solo in contesti di puntatore che NULLe 0sono equivalenti. NULLnon dovrebbe essere usato quando 0è richiesto un altro tipo di , anche se potrebbe funzionare, perché in questo modo si invia un messaggio stilistico errato. (Inoltre, ANSI consente la definizione di NULLessere ((void *)0), che non funzionerà affatto in contesti senza puntatore.) In particolare, non utilizzare NULLquando NULsi desidera il carattere null ASCII ( ). Fornisci la tua definizione

#define NUL '\0'

se devi.


5

Qual è la differenza tra NULL, '\ 0' e 0

"null character (NUL)" è il più facile da escludere. '\0'è un personaggio letterale. In C, è implementato come int, quindi, è uguale a 0, che è di INT_TYPE_SIZE. In C ++, il carattere letterale è implementato come char, ovvero 1 byte. Questo è normalmente diverso da NULLo 0.

Successivamente, NULLè un valore del puntatore che specifica che una variabile non punta a nessuno spazio degli indirizzi. Metti da parte il fatto che di solito è implementato come zeri, deve essere in grado di esprimere l'intero spazio degli indirizzi dell'architettura. Pertanto, su un'architettura a 32 bit NULL (probabilmente) è a 4 byte e su architettura a 64 bit a 8 byte. Questo dipende dall'implementazione di C.

Infine, il letterale 0è di tipo int, che è di dimensioni INT_TYPE_SIZE. Il valore predefinito di INT_TYPE_SIZEpotrebbe essere diverso a seconda dell'architettura.

Apple ha scritto:

Il modello di dati a 64 bit utilizzato da Mac OS X è noto come "LP64". Questo è il modello di dati comune utilizzato da altri sistemi UNIX a 64 bit di Sun e SGI e Linux a 64 bit. Il modello di dati LP64 definisce i tipi primitivi come segue:

  • gli ints sono a 32 bit
  • i long sono a 64 bit
  • i long-long sono anche a 64 bit
  • i puntatori sono a 64 bit

Wikipedia a 64 bit :

Il compilatore VC ++ di Microsoft utilizza il modello 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       ?

Modifica : aggiunto altro sul carattere letterale.

#include <stdio.h>

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

Il codice sopra riportato restituisce 4 su gcc e 1 su g ++.


2
No, non'\0' è un valore di 1 byte. È un carattere letterale, che è un'espressione costante intera - quindi se si può dire che abbia una dimensione, allora è la dimensione di un (che deve essere di almeno 2 byte). Se non mi credi, valuta e vedi di persona. , E sono tutti del tutto equivalenti. intsizeof('\0')'\0'00x0
Caf

@caf dipende dalla lingua. Se non mi credi, prova sizeof('\0')un compilatore C ++.
Eugene Yokota,

2
dovresti usare "% zu" quando stampi sizeof (qualcosa)
Inutilizzato il

4

Un NUL di una L, termina una stringa.

Un NULL di due L non indica nulla.

E scommetterò un toro d'oro

Che non esiste una NULLL da tre L.

Come gestisci NUL?


4

Un buon pezzo che mi aiuta quando inizio con C (Tratto dall'esperto C Programming di Linden)

L'uno 'n' e i due 'l' null

Memorizza questa piccola rima per ricordare la terminologia corretta per i puntatori e zero ASCII:

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. 

Il carattere ASCII con il modello di bit zero è definito "NUL". Il valore del puntatore speciale che indica che il puntatore non punta da nessuna parte è "NULL". I due termini non sono intercambiabili nel significato.


Molto più semplice: NULè un codice di controllo, come BEL, VT, HT, SOTecc e quindi ha max. 3 personaggi.
glglgl

2

"NUL" non è 0, ma si riferisce al carattere ASCII NUL. Almeno, è così che l'ho visto usato. Il puntatore null è spesso definito come 0, ma questo dipende dall'ambiente in cui si esegue e dalle specifiche del sistema operativo o della lingua in uso.

In ANSI C, il puntatore null è specificato come valore intero 0. Quindi qualsiasi mondo in cui ciò non è vero non è conforme a ANSI C.


1

Un byte con un valore di 0x00è, nella tabella ASCII, il carattere speciale chiamato NULo NULL. In C, dal momento che non dovresti incorporare caratteri di controllo nel tuo codice sorgente, questo è rappresentato in stringhe C con uno 0 di escape, ovvero \0.

Ma un vero NULL non è un valore. È l'assenza di un valore. Per un puntatore, significa che il puntatore non ha nulla a cui puntare. In un database, significa che non esiste alcun valore in un campo (che non è la stessa cosa che dire che il campo è vuoto, 0 o pieno di spazi).

Il valore effettivo utilizzato da un determinato sistema o formato di file di database per rappresentare un NULLnon è necessariamente 0x00.


0

NULLnon è garantito essere 0 - il suo valore esatto dipende dall'architettura. La maggior parte delle architetture principali lo definisce (void*)0.

'\0' sarà sempre uguale a 0, perché è così che il byte 0 è codificato in un carattere letterale.

Non ricordo se i compilatori C debbano usare ASCII - in caso contrario, '0'potrebbe non essere sempre uguale a 48. Indipendentemente da ciò, è improbabile che incontrerai mai un sistema che utilizza un set di caratteri alternativo come EBCDIC a meno che tu non stia lavorando molto sistemi oscuri.

Le dimensioni dei vari tipi differiranno sui sistemi a 64 bit, ma i valori interi saranno gli stessi.


Alcuni commentatori hanno espresso il dubbio che NULL sia uguale a 0, ma non sia zero. Ecco un programma di esempio, insieme all'output previsto su un tale sistema:

#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;
}

Quel programma potrebbe stampare:

NULL == 0
NULL = 0x00000001

2
OP stava chiedendo "\ 0" (il carattere NUL), non "0" (il carattere zero)
Chris Lutz,

2
@Chris: '\ 0' non è NULL, è byte 0 codificato in ottale in un carattere letterale.
John Millikin,

2
In C ++, lo standard garantisce che la conversione dal valore intero 0 in un puntatore genererà sempre un puntatore nullo. In C ++, 0 è garantito come puntatore null, mentre NULL invece è una macro e un programmatore dannoso potrebbe ridefinirlo come qualcosa di diverso.
David Rodríguez - dribeas,

6
E NULL è garantito per essere 0. Il modello di bit di un puntatore NULL non è garantito per essere tutti zeri, ma la costante NULL è, e sarà sempre, 0.
jalf

2
La tua prima frase è sbagliata - NULL non può essere definito come (void *) 0 in C ++ perché non esiste una conversione implicita da un void * a un altro puntatore (diversamente da C).

-2

(void *) 0 è NULL e '\ 0' rappresenta la fine di una stringa.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.