2011-12-22 11 views
5

Encontré un error en mi código donde comparé el puntero con '\ 0'.¿Por qué está bien comparar un puntero con ' 0'? (pero no 'A')

Preguntándome por qué el compilador no me advirtió sobre este error, intenté lo siguiente.

#include <cassert> 

struct Foo 
{ 
    char bar[5]; 
}; 

int main() 
{ 
    Foo f; 
    Foo* p = &f; 
    p->bar[0] = '\0'; 
    assert(p->bar == '\0'); // #1. I forgot [] Now, comparing pointer with NULL and fails. 
    assert(p->bar == 'A');  // #2. error: ISO C++ forbids comparison between pointer and integer 
    assert(p->bar[0] == '\0'); // #3. What I intended, PASSES 
    return 0; 
} 

¿Qué tiene especial sobre '\ 0' que hace que # 1 legal y # 2 sean ilegales?

Por favor, agrega una referencia o presupuesto a tu respuesta.

Respuesta

8

Lo que lo hace legal y bien definido es el hecho de que '\0' es un puntero nulo constante por lo que se puede convertir en cualquier tipo de puntero para hacer un valor de puntero nulo .

ISO/IEC 14882: 2011 4.10 [conv.ptr]/1:

A puntero nulo constante es un prvalue integral constante expresión de tipo entero que se evalúa como cero o un prvalue de tipo std::nullptr_t . Una constante de puntero nulo se puede convertir a un tipo de puntero; el resultado es el valor de puntero nulo de ese tipo y se distingue de cualquier otro valor de puntero de objeto o tipo de puntero a función. Dicha conversión se llama conversión de puntero nulo.

'\0' cumple con los requisitos de "integral prvalue expresión constante de tipo entero que evalúa a cero" porque char es un tipo entero y \0 tiene el valor cero.

Otros enteros solo se pueden convertir explícitamente a un tipo de puntero a través de reinterpret_cast y el resultado solo es significativo si el entero fue el resultado de convertir un puntero válido a un tipo entero de tamaño suficiente.

5

'\0' es simplemente una forma diferente de escribir 0. Supongo que esto es comparar legalmente punteros a 0 tiene sentido, no importa cómo se escribió el 0, mientras que casi nunca hay ningún significado válido para comparar un puntero a cualquier otro tipo de no puntero.

+1

y 0 se convierte en 'nullptr' (en el lenguaje C++ 11) –

+1

@BasileStarynkevitch, no creo que sea en este caso. La constante del puntero nulo se convierte directamente en el valor del puntero nulo del tipo apropiado. – avakar

+0

Pero 'nullptr' denota el valor del puntero nulo del tipo apropiado ... –

1

Este es un error de diseño de C++. La regla dice que cualquier expresión constante entera con valor cero se puede considerar como la constante de puntero nulo.

Este idiota decisión muy cuestionable permite utilizar puntero nulo '\0' (como lo encontró), sino también cosas como (1==2) o incluso !!!!!!!!!!!1 (un ejemplo similar a uno que está presente en "El lenguaje de programación C++", ni idea si Stroustrup piensa que esto es realmente una característica "genial").

Esta ambigüedad IMO incluso crea una laguna en la definición de sintaxis cuando se mezcla con reglas de conversiones semánticas e implícitas de operadores ternarios: recuerdo haber encontrado un caso en el que uno de tres compiladores no estaba compilando y los otros dos compilaban con semántica diferente ... y después de perder un día leyendo el estándar y preguntando a expertos en cclC++. m, no pude decidir cuál de los tres compiladores tenía razón.

+0

¿No sería un error de diseño en C, teniendo en cuenta que esta característica se heredó de ella? (No es que esté de acuerdo con usted sobre la idiotez de esas decisiones) – avakar

+0

@avakar: No lo creo. En realidad, las reglas C y C++ para el puntero nulo son diferentes y también las reglas de conversión de tipo para C++ son mucho más complejas, por lo que no existe una "compatibilidad hacia atrás" real. Por ejemplo, el '#define NULL (* void *) 0)' bastante común que se usa (se usa) en los encabezados del sistema C no es una definición 'NULL' válida para C++. – 6502

+0

No es que importe, pero ¿cuál fue el caso que recuerda? –

Cuestiones relacionadas