2010-11-25 15 views
11

Se planteó la cuestión en los comentarios de una respuesta a la pregunta Is C/C++ bool type always guaranteed to be 0 or 1 when typecast'ed to int?¿Está leyendo un comportamiento indefinido de valor indeterminado?

El código en cuestión asigna una matriz (local) de bool sin inicializar su valor.

const int n = 100; 
bool b[n]; 

Claramente los valores en b son indeterminados.

Algunos de los comentaristas opinaron que, por ejemplo, leer b[0] era un comportamiento indefinido. ¿Esto está establecido en cualquier lugar del estándar C++? Todavía estoy convencido de lo contrario:

  1. Existe claramente asigna el almacenamiento y la inicialización del tipo bool fundamental es completa, ya que no tiene un constructor. Por lo tanto, ciertamente no es lo mismo que desreferenciar un puntero no inicializado o llamar a los operadores de métodos/colada en objetos no triviales no inicializados. Estos casos específicos parecen estar cubiertos por el estándar.

  2. El comportamiento de hecho no está definido en C: What happens to a declared, uninitialized variable in C? Does it have a value? y algunos encuestados parecen confundir a los dos.

  3. En el último borrador de C++ 0x no puedo encontrar ninguna definición de valor indeterminado especialmente ninguna definición que permita acceder a dicho valor para activar un procesador de trampa. De hecho, Bjarne Stroustrup no está seguro de lo que puede ser un valor inderminate: http://zamanbakshifirst.blogspot.com/2007/02/c-indeterminate-value.html

+1

Ah, bueno, "Comportamiento indefinido" es un término muy favorito aquí en StackOverflow y se usa para todo, desde la definición de la implementación, hasta el indefinido hasta el no definido. –

+1

Me refiero a los proverbiales "demonios nasales" como indefinidos. – Sebastian

+0

Y por cierto. 8.5 - 9 habla sobre esto. –

Respuesta

4

sí, formalmente una conversión rvalue de valor indeterminado es UB (a excepción de unsigned char, escribí originalmente "y variantes", pero por lo que recuerdo la Especial formales para complementar firmado carbón de 1, donde posiblemente menos 0 podría ser utilizado como valor de interrupciones)

soy demasiado perezoso para hacer la búsqueda del párrafo estándar para usted, y también para perezoso para cuidar de downvotes para que

sin embargo, en la práctica solo un problema en (1) arquitecturas arcaicas, y tal vez (2) sistemas de 64 bits.

EDIT: uy, ahora parece recordar una publicación en un blog y el Informe de Defecto asociado sobre UB formal para acceder al carácter indeterminado. así que tal vez tenga que verificar el estándar, + DR de búsqueda. argh, tendrá que ser más tarde entonces, ¡ahora café!

Edit2: Johannes Schaub fue tan amable de proporcionar esta link to SO question donde se discutió que la UB para acceder a carbón. Entonces, ¡de eso es de lo que lo recordaba! Gracias, Johannes.

.

aplausos & HTH,

+0

@downvoter: indique la razón de la votación a la baja para que otros puedan enterarse de lo que ocurre con una respuesta o por qué su voto negativo es tonto. –

+5

+1. 4.1/1: "Un lvalue (3.10) de un tipo T no funcional, no de matriz se puede convertir a un valor r. Si T es un tipo incompleto, un programa que necesita esta conversión está mal formado. que el valor l se refiere no es un objeto de tipo T y no es un objeto de un tipo derivado de T, o si el objeto no está inicializado, un programa que necesita esta conversión tiene un comportamiento indefinido ". –

+1

Oye, no te rechazaré por tu pereza. Sin embargo, es posible que tampoco lo haya votado a favor. – Default

3

En bool, la norma dice bajo 3.9.1 tipos fundamentales:

Los valores de tipo bool son verdaderas o falsas .

Con una nota al pie que dice:

Usando un valor bool en formas descritas por esta norma internacional como “indefinido”, como examinando el valor de un sin inicializar automática de objetos , puede hacer que se comporte como si no fuera verdadero ni falso.

5

la respuesta a esta pregunta cambia con el último borrador de trabajo 1a ++ C (N3946), que podemos encontrar here. Sección 8.5Inicializadores el párrafo 12 cambia mucho de C++ y C++ 03 11 y ahora contiene la siguiente (el énfasis es mío ):

Si no se especifica un inicializador para un objeto, el objeto es inicializado por defecto. Cuando se obtiene de almacenamiento para un objeto con automático o duración de almacenamiento dinámico, el objeto tiene un valorindeterminado , y si no se efectúa la inicialización para el objeto, que objeto retiene un valor indeterminado hasta que se sustituye dicho valor (5.17). [Nota: los objetos con duración de almacenamiento estático o de subprocesos son con inicialización cero, consulte 3.6.2. - nota final] Si un valor indeterminado es producido por una evaluación, el comportamiento no está definido, excepto en los siguientes casos:

y pasa a la lista algunas excepciones para sin firmar tipo de carácter estrecha solamente, Tengo una cita completa en Has C++1y changed with respect to the use of indeterminate values and undefined behavior?.

Por lo tanto, en su caso b tiene una duración de almacenamiento automática y no se inicializa, por lo que tiene un valor indeterminado. Entonces, evaluar b[0] es un comportamiento indefinido.

Anteriormente, teníamos que usar la conversión lvalue-to-rvalue para probar que esto no estaba definido, pero eso es problemático desde the conversion is underspecified.

Tenga en cuenta que el valor indeterminado está en cursiva en esta sección y, por lo tanto, significa que se está definiendo en su lugar, por lo que ahora C++ 1y realmente define el término. Anteriormente el término se usó sin una definición, esto se cubre en defect report 616.

0

El hecho de que leer un valor indeterminado generalmente da como resultado un comportamiento indefinido no es simplemente un problema "teórico". Incluso para los tipos en los que todos los patrones de bits posibles tienen valores definidos, no debe considerarse "sorprendente" que los valores indeterminados se comporten de forma distinta a los valores no especificados.Por ejemplo, si * p mantiene indeterminada valor y, x no se utiliza en cualquier lugar excepto como se muestra, el código:

uint32_t x,y,z; 
... 
x = *p; 
if (condition1) y=x; 
... code that "shouldn't" affect *p if its value is defined 
if (condition2) z=x; 

podría reescribirse como:

if (condition1) y=*p; 
... code that "shouldn't" affect *p if its value is defined 
if (condition2) z=*p; 

Si el valor de * p es Indeterminado, un compilador no estaría prohibido por tener el código entre las dos declaraciones "if" que modifican su valor. Por ejemplo, si el almacenamiento ocupado por * p estuvo ocupado por un "flotante" antes de liberarlo y volverlo a malloc, el compilador podría escribir ese valor "flotante" entre las dos declaraciones "if" anteriores.

Cuestiones relacionadas