¿Cuál es la diferencia entre NULL, '\0' y 0?
En C, parece haber diferencias entre varios valores de cero NULL
-- NUL
y 0
.
Sé que el carácter ASCII '0'
se evalúa como 48
o 0x30
.
El NULL
puntero generalmente se define como:
#define NULL 0
O
#define NULL (void *)0
Además, está el NUL
personaje '\0'
que parece evaluar 0
también.
¿Hay ocasiones en las que estos tres valores no pueden ser iguales?
¿Esto también se aplica a los sistemas de 64 bits?
Nota: Esta respuesta se aplica al lenguaje C, no a C++.
Punteros nulos
El literal constante entero 0
tiene diferentes significados según el contexto en el que se utiliza. En todos los casos, sigue siendo una constante entera con el valor 0
, simplemente se describe de diferentes maneras.
Si se compara un puntero con el literal constante 0
, entonces se trata de una verificación para ver si el puntero es un puntero nulo. Esto 0
se denomina entonces constante de puntero nulo. El estándar C define que 0
la conversión al tipo void *
es tanto un puntero nulo como una constante de puntero nulo.
Además, para facilitar la lectura, la macro NULL
se proporciona en el archivo de encabezado stddef.h
. Dependiendo de su compilador, podría ser posible #undef NULL
redefinirlo como algo extraño.
Por lo tanto, aquí hay algunas formas válidas de comprobar si hay un puntero nulo:
if (pointer == NULL)
NULL
se define para comparar igual a un puntero nulo. La implementación define cuál es la definición real NULL
, siempre que sea una constante de puntero nulo válida.
if (pointer == 0)
0
es otra representación de la constante de puntero nulo.
if (!pointer)
Esta if
declaración verifica implícitamente "no es 0", por lo que lo invertimos para que signifique "es 0".
Las siguientes son formas NO VÁLIDAS de comprobar si hay un puntero nulo:
int mynull = 0;
<some code>
if (pointer == mynull)
Para el compilador, esto no es una verificación de un puntero nulo, sino una verificación de igualdad de dos variables. Esto podría funcionar si mynull nunca cambia en el código y la constante de optimización del compilador agrega el 0 a la declaración if, pero esto no está garantizado y el compilador debe producir al menos un mensaje de diagnóstico (advertencia o error) de acuerdo con el estándar C.
Tenga en cuenta que el valor de un puntero nulo en el lenguaje C no importa en la arquitectura subyacente. Si la arquitectura subyacente tiene un valor de puntero nulo definido como dirección 0xDEADBEEF, entonces le corresponde al compilador solucionar este problema.
Como tal, incluso en esta curiosa arquitectura, las siguientes formas siguen siendo válidas para comprobar si hay un puntero nulo:
if (!pointer)
if (pointer == NULL)
if (pointer == 0)
Las siguientes son formas NO VÁLIDAS de comprobar si hay un puntero nulo:
#define MYNULL (void *) 0xDEADBEEF
if (pointer == MYNULL)
if (pointer == 0xDEADBEEF)
ya que un compilador los considera comparaciones normales.
Caracteres nulos
'\0'
se define como un carácter nulo, es decir, un carácter con todos los bits establecidos en cero. '\0'
es (como todos los caracteres literales) una constante entera, en este caso con el valor cero. So '\0'
es completamente equivalente a una 0
constante entera sin adornos; la única diferencia está en la intención que transmite a un lector humano ("Estoy usando esto como un carácter nulo").
'\0'
No tiene nada que ver con punteros. Sin embargo, es posible que vea algo similar a este código:
if (!*char_pointer)
comprueba si el puntero char apunta a un carácter nulo.
if (*char_pointer)
comprueba si el puntero char apunta a un carácter no nulo.
No los confunda con punteros nulos. Sólo porque la representación de bits es la misma, y esto permite algunos casos de cruce convenientes, en realidad no son lo mismo.
Referencias
Consulte la pregunta 5.3 de las preguntas frecuentes de comp.lang.c para obtener más información. Consulte este pdf para conocer el estándar C. Consulte las secciones 6.3.2.3 Consejos, párrafo 3.
Parece que varias personas no entienden cuáles son las diferencias entre NULL, '\0' y 0. Entonces, para explicar, y en un intento de evitar repetir lo dicho anteriormente:
Una expresión constante de tipo int
con el valor 0, o una expresión de este tipo, convertida a tipo void *
es una constante de puntero nulo , que si se convierte en un puntero se convierte en un puntero nulo . El estándar garantiza la comparación desigual con cualquier puntero a cualquier objeto o función .
NULL
es una macro, definida como una constante de puntero nulo .
\0
es una construcción utilizada para representar el carácter nulo , que se utiliza para terminar una cadena.
Un carácter nulo es un byte que tiene todos sus bits puestos a 0.
Los tres definen el significado de cero en diferentes contextos.
- Contexto del puntero: se utiliza NULL y significa que el valor del puntero es 0, independientemente de si es de 32 bits o de 64 bits (en un caso, 4 bytes y en el otro, 8 bytes de ceros).
- contexto de cadena: el carácter que representa el dígito cero tiene un valor hexadecimal de 0x30, mientras que el carácter NUL tiene un valor hexadecimal de 0x00 (utilizado para terminar cadenas).
Estos tres siempre son diferentes cuando miras el recuerdo:
NULL - 0x00000000 or 0x00000000'00000000 (32 vs 64 bit)
NUL - 0x00 or 0x0000 (ascii vs 2byte unicode)
'0' - 0x20
Espero que esto lo aclare.