que - ¿Cómo verificamos si un puntero es un puntero NULL?
punteros en c ejemplos (7)
Siempre pienso simplemente if(p != NULL){..}
hará el trabajo. Pero después de leer esta pregunta sobre el desbordamiento de pila , parece que no.
Entonces, ¿cuál es la forma canónica de buscar punteros NULL después de absorber toda la discusión en esa pregunta que dice que los punteros NULL pueden tener un valor distinto de cero?
Siempre pienso simplemente si (p! = NULL) {..} hará el trabajo.
Va a.
Aparentemente, el hilo que refieres es sobre C++
.
En C
su fragmento siempre funcionará. Me gusta más simple if (p) { /* ... */ }
.
Bueno, esta pregunta fue formulada y respondida allá por 2011, pero hay nullptr
en C++11 . Eso es todo lo que estoy usando actualmente.
Puede leer más de y también de este artículo .
El compilador debe proporcionar un sistema de tipo consistente y proporcionar un conjunto de conversiones estándar. Ni el valor entero 0 ni el puntero NULL deben representarse con bits cero, pero el compilador debe ocuparse de convertir el token "0" en el archivo de entrada en la representación correcta para el entero cero, y el molde en el tipo de puntero debe convertir de entero a representación de puntero.
La implicación de esto es que
void *p;
memset(&p, 0, sizeof p);
if(p) { ... }
no se garantiza que se comporte igual en todos los sistemas de destino, ya que se está asumiendo el patrón de bits aquí.
Como ejemplo, tengo una plataforma incrustada que no tiene protección de memoria y mantiene los vectores de interrupción en la dirección 0, por lo tanto, por convención, los enteros y punteros son XORed con 0x2000000 cuando se convierten, lo que deja (vacío *) 0 apuntando a una dirección que genera un error de bus cuando se desreferencia, sin embargo, probar el puntero con una instrucción if
lo devolverá primero a la representación entera, que luego es ceros al máximo.
La representación de punteros es irrelevante para compararlos, ya que todas las comparaciones en C tienen lugar como valores, no como representaciones. La única forma de comparar la representación sería algo horrible como:
static const char ptr_rep[sizeof ptr] = { 0 };
if (!memcmp(&ptr, ptr_rep, sizeof ptr)) ...
La representación real de un puntero nulo es irrelevante aquí. Un literal entero con valor cero (incluyendo 0
y cualquier definición válida de NULL
) se puede convertir a cualquier tipo de puntero, dando un puntero nulo, cualquiera que sea la representación real. Entonces p != NULL
, p != 0
p
son todas pruebas válidas para un puntero no nulo.
Puede tener problemas con representaciones distintas de cero del puntero nulo si escribió algo retorcido como p != reinterpret_cast<void*>(0)
, por lo tanto, no haga eso.
Aunque acabo de notar que su pregunta está etiquetada C y C ++. Mi respuesta se refiere a C ++, y otros idiomas pueden ser diferentes. ¿Qué idioma estás usando?
Primero, para ser 100% claro, no hay diferencia entre C y C ++ aquí. Y segundo, la pregunta sobre el desbordamiento de pila que citan no habla de punteros nulos; introduce punteros inválidos; punteros que, al menos en lo que respecta al estándar, causan un comportamiento indefinido simplemente al tratar de compararlos. No hay forma de probar en general si un puntero es válido.
Al final, hay tres formas muy extendidas de buscar un puntero nulo:
if ( p != NULL ) ...
if ( p != 0 ) ...
if ( p ) ...
Todo funciona, independientemente de la representación de un puntero nulo en la máquina. Y todos, de una manera u otra, son engañosos; cuál elegir es una cuestión de elegir el menos malo. Formalmente, los primeros dos son idénticos para el compilador; la constante NULL
o 0
se convierte en un puntero nulo del tipo de p
, y los resultados de la conversión se comparan con p
. Independientemente de la representación de un puntero nulo.
El tercero es ligeramente diferente: p
se convierte implícitamente en bool
. Pero la conversión implícita se define como el resultado de p != 0
, por lo que terminas con lo mismo. (Lo que significa que realmente no hay un argumento válido para usar el tercer estilo; se ofusca con una conversión implícita, sin ningún beneficio de compensación).
Cuál de los dos primeros prefieres es en gran medida una cuestión de estilo, quizás parcialmente dictada por tu estilo de programación en otra parte: según el idioma involucrado, una de las mentiras será más molesta que la otra. Si fuera solo una cuestión de comparación, creo que la mayoría de la gente preferiría NULL
, pero en algo como f( NULL )
, la sobrecarga que se elegirá es f( int )
y no una sobrecarga con un puntero. De forma similar, si f
es una plantilla de función, f( NULL )
instanciará la plantilla en int
. (Por supuesto, algunos compiladores, como g ++, generarán una advertencia si se usa NULL
en un contexto no puntero, si usas g ++, deberías usar NULL
).
En C++11 , por supuesto, la expresión preferida es:
if ( p != nullptr ) ...
, que evita la mayoría de los problemas con las otras soluciones. (Pero no es compatible con C :-).)