vacio - ¿NULL siempre es cero en C?
objeto nulo c++ (5)
Estuve entrevistando ayer a un tipo para una posición de ingeniería de software de nivel medio, y mencionó que en C, NULL no siempre es cero y que había visto implementaciones de C donde NULL no es cero. Encuentro esto altamente sospechoso, pero quiero estar seguro. Alguien sabe si él tiene razón?
(Las respuestas no afectarán mi juicio sobre este candidato, ya presenté mi decisión a mi gerente).
El § 6.3.2.3 del estándar C99 dice
Una expresión constante entera con el valor 0, o una expresión de este tipo para escribir void *, se llama constante de puntero nulo. Si una constante de puntero nulo se convierte en un tipo de puntero, se garantiza que el puntero resultante, llamado puntero nulo, compare desigual a un puntero a cualquier objeto o función.
El § 7.17 también dice
[...] NULL que se expande a una constante de puntero nulo definido en la implementación [...]
La dirección del puntero NULL puede ser diferente de 0, mientras que se comportará como en la mayoría de los casos.
(Esto debería ser el mismo que en los antiguos estándares de C, que no tengo a mano en este momento)
En C, hay uno, y solo uno, contexto en el que es necesario emitir explícitamente una constante de puntero nulo a un tipo de puntero específico para que el programa funcione correctamente. Ese contexto pasa un puntero nulo a través de una lista de argumentos de la función sin tipo. En la C moderna , esto solo ocurre cuando necesita pasar un puntero nulo a una función que toma una cantidad variable de argumentos. (En el C heredado, sucede con cualquier función no declarada con un prototipo.) El ejemplo paradigmático es execl
, donde el último argumento debe ser un puntero nulo explícitamente lanzado a (char *)
:
execl("/bin/ls", "ls", "-l", (char *)0); // correct
execl("/bin/ls", "ls", "-l", (char *)NULL); // correct, but unnecessarily verbose
execl("/bin/ls", "ls", "-l", 0); // undefined behavior
execl("/bin/ls", "ls", "-l", NULL); // ALSO undefined behavior
Sí, ese último ejemplo tiene un comportamiento indefinido incluso si NULL
se define como ((void *)0)
, porque void *
y char *
no son implícitamente interconvertibles cuando se pasan a través de una lista de argumentos sin tipo, aunque se encuentren en cualquier otro lugar.
"Debajo del capó", el problema aquí no es solo con el patrón de bits utilizado para un puntero nulo, sino que el compilador puede necesitar saber el tipo concreto exacto de cada argumento para configurar un marco de llamada correctamente. (Considere el MC68000, con su dirección y registros de datos separados, algunos ABI especifican argumentos de puntero para pasar en registros de direcciones pero argumentos enteros en registros de datos. Considere también cualquier ABI donde int
y void *
no tienen el mismo tamaño. Y es extremadamente raro hoy en día, pero C todavía proporciona explícitamente que void *
y char *
no tengan el mismo tamaño). Si hay un prototipo de función, el compilador puede usar eso, pero las funciones sin prototipo y los argumentos variados no ofrecen tal ayuda.
C ++ es más complicado y no me siento capacitado para explicar cómo.
La constante del puntero nulo es siempre 0. La macro NULL
puede definirse mediante la implementación como 0
desnudo, o una expresión moldeada como (void *) 0
, o alguna otra expresión entera de valor cero (de ahí el lenguaje "implementación definida" en el estandar).
El valor del puntero nulo puede ser distinto de 0. Cuando se encuentra una constante de puntero nulo, se convertirá al valor del puntero nulo apropiado.
Supongo que te refieres al puntero nulo. Está garantizado para comparar igual a 0
. 1 Pero no tiene que ser representado con bits a cero. 2
Consulte también las preguntas frecuentes sobre comp.lang.c sobre punteros nulos.
- Ver C99, 6.3.2.3.
- No hay un reclamo explícito; pero vea la nota al pie para C99, 7.20.3 (gracias a @birryree en los comentarios).
Tiene razón, en algunas implementaciones, el tamaño del puntero no es el mismo que el tamaño del número entero. NULL en el contexto entero es 0, pero el diseño binario real no tiene que ser todo 0s.