Espacios de nombres
Variantes
Acciones

Comportamiento no definido

De cppreference.com
< cpp‎ | language

La violación de ciertas reglas del lenguaje hace que el programa no tenga sentido.

Contenido

[editar]Explicación

El estándar de C++ define con precisión el comportamiento observable de cada programa de C++ que no pertenece a una de las siguientes clases:

  • Mal formado. El programa tiene errores de sintaxis y semánticos detectables. Se requiere un compilador conforme para realizar un diagnóstico, incluso si se define una extensión del lenguaje que asigna significado a dicho código (como los arrays de longitud variable). El texto del estándar usa deberá, no deberá, y mal formado para indicar estos requisitos.
  • Mal formado, no se requiere diagnóstico. El programa tiene errores semánticos que no son diagnosticables en el caso general (por ejemplo, violaciones de la regla ODR u otros errores que sólo se pueden detectar en la fase de enlazado). El comportamiento no está definido si se ejecuta tal programa.
  • Comportamiento definido por la implementación. El comportamiento del programa varía entre distintas implementaciones, y la implementación conforme debe documentar los efectos de cada comportamiento. Por ejemplo, el tipo std::size_t o el número de bits en un byte, o el texto de std::bad_alloc::what. Un subconjunto del comportamiento definido por la implementación es comportamiento específico de la configuración regional, que depende de la configuración regional proporcionada por la implementación.
  • Comportamiento no especificado. El comportamiento del programa cambia entre implementaciones y no es necesario que una implementación conforme documente los efectos de cada comportamiento. Por ejemplo, el orden de evaluación, si los literales de cadena idénticos son distintos, la cantidad del sobredimensionamiento en la asignación de memoria de arrays, etc. Cada comportamiento resulta en uno de los resultados válidos de un conjunto.
  • Comportamiento no definido. No hay restricciones en el comportamiento del programa. Ejemplos son: carreras de datos, acceso a memoria fuera de los límites del array, desbordamiento de enteros con signo, desreferencia de un puntero nulo, modificaciones al mismo escalar más de una vez en una expresión sin ningún punto de secuencia intermedio(hasta C++11)que está sin secuenciar(desde C++11), acceso a un objeto a través de un puntero de tipo diferente, etc. No se requiere que los compiladores diagnostiquen el comportamiento no definido (aunque se diagnostican muchas situaciones simples), y el programa compilado no está obligado a hacer nada significativo.

[editar]Optimización y comportamiento no definido

Debido a que los programas C++ correctos están libres de un comportamiento no definido, los compiladores pueden producir resultados inesperados cuando un programa que realmente tiene un comportamiento no definido se compila con la optimización habilitada:

Por ejemplo,

[editar]Desbordamiento de signo

int foo(int x){return x+1> x;// puede ser verdadero o no definido// debido al desbordamiento de signo}

puede compilarse como (demo)

foo(int): movl $1, %eax ret

[editar]Acceso fuera de los límites

int table[4]={};bool exists_in_table(int v){// devuelve verdadero en una de las 4 primeras iteraciones// o no definido por un acceso fuera de los límitesfor(int i =0; i <=4; i++){if(table[i]== v)returntrue;}returnfalse;}

puede compilarse como (demo)

exists_in_table(int): movl $1, %eax ret

[editar]Escalar sin inicializar

std::size_t f(int x){std::size_t a;if(x)// x debe ser distinto de cero o el comportamiento no está definido a =42;return a;}

se puede compilar como (demo)

f(int): mov eax, 42 ret

El resultado que se muestra se observó en una versión antigua de gcc

bool p;// variable local sin inicializarif(p)// comportamiento no definido, acceso a escalar sin inicializarstd::puts("p es verdadero");if(!p)// comportamiento no definido, acceso a escalar sin inicializarstd::puts("p es falso");

Posible salida:

p es verdadero p es falso

[editar]Desreferencia (indirección) de puntero nulo

int foo(int* p){int x =*p;if(!p)return x;// o no definido arriba o esta rama nunca se tomaelsereturn0;}int bar(){int* p = nullptr;return*p;// Comportamiento no definido incondicional}

se puede compilar como (foo con gcc, bar con clang)

foo(int*): xorl %eax, %eax ret bar(): retq

[editar]Acceso a puntero pasado a realloc

Seleccione clang para ver el resultado de salida

#include <iostream>#include <cstdlib>int main(){int*p =(int*)std::malloc(sizeof(int));int*q =(int*)std::realloc(p, sizeof(int));*p =1;// Comportamiento no definido de acceso a puntero que se paso a realloc*q =2;if(p == q)// Comportamiento no definido de acceso a puntero que se paso a reallocstd::cout<<*p <<*q <<'\n';}

Posible salida:

12

[editar]Bucle infinito sin efectos secundarios

Seleccione clang para ver el resultado de salida

#include <iostream>   int fermat(){constint MAX =1000;int a=1,b=1,c=1;// Bucle infinito sin efectos secundarios en un comportamiento no definidowhile(1){if(((a*a*a)==((b*b*b)+(c*c*c))))return1; a++;if(a>MAX){ a=1; b++;}if(b>MAX){ b=1; c++;}if(c>MAX){ c=1;}}return0;}   int main(){if(fermat())std::cout<<"El último teorema de Fermat ha sido refutado.\n";elsestd::cout<<"El último teorema de Fermat no ha sido refutado.\n";}

Posible salida:

El último teorema de Fermat ha sido refutado.

[editar]Enlaces externos

[editar]Véase también

Documentación de C para Comportamiento no definido
close