Comportamiento no especificado en C/C++ con ejemplos

Los usuarios de C y C++ utilizan la terminología de comportamiento no especificado . Se define como Anexo-J del estándar C11. Aprendamos más sobre esta terminología.

Tipo 1. Orden de evaluación de los argumentos de la función:

Se dice que un programa tiene un comportamiento no especificado cuando el estándar proporciona dos o más posibilidades pero no impone requisitos sobre cuál debe elegir el escritor del compilador. Por ejemplo, ¡no se especifica el orden en que se llaman las funciones fun1 y fun2 en la siguiente expresión!

x = diversión1() + diversión2();

El compilador puede optar por implementarlo de izquierda a derecha o de derecha a izquierda, lo que da como resultado que se llame primero a fun1 o fun2 . El estándar no detecta el orden de llamada.

El comportamiento indefinido da como resultado un comportamiento imprevisto de todo el programa. Pero en un comportamiento no especificado, el programa elige en un cruce particular y continúa como de costumbre, como se ejecuta originalmente la función.

A continuación se muestra el programa para ilustrar el comportamiento no especificado:

C

// C program to illustrate Unspecified
// Behaviour
#include <stdio.h>
  
// Declaring x as a global variable
// defining fun1
int x;
  
// Defining function fun1()
int fun1()
{
    x = 5;
    return 2;
}
  
// Defining function fun2()
int fun2()
{
    x = 10;
    return 3;
}
  
// Driver Code
int main()
{
    // Function call
    int sum = fun1() + fun2();
  
    // Printing the value of x
    printf("%d", x);
    return 0;
}

C++

// C++ program to illustrate Unspecified
// Behaviour
#include <iostream>
using namespace std;
  
// Declaring x as a global variable
// defining fun1
int x;
  
// Defining function fun1()
int fun1()
{
    x = 5;
    return 2;
}
  
// Defining function fun2()
int fun2()
{
    x = 10;
    return 3;
}
  
// Driver Code
int main()
{
    // Function call
    int sum = fun1() + fun2();
  
    // Print the value of x
    cout << x;
    return 0;
}
Producción:

10

Explicación:

Inicialmente, en el programa anterior, x es 0. fun1() cambia x a 5 y devuelve 2. fun2() cambia x a 10 y devuelve 3. El valor de la suma es definitivamente 5, x es una variable global y las tres funciones acceden la misma x global. Si una función está cambiando x, está cambiando la misma copia de x que otro acceso.

Las dos llamadas de función son operandos del operador +(sumar) si el operador más evalúa sus operandos de izquierda a derecha, entonces se llamará a fun1 primero configurando el valor de x-5, luego se llamará a fun2 configurando el valor final de x como 10

De manera similar, si el orden de evaluación es de derecha a izquierda, el valor final de x será 10, ya que en fun1 se llamará el último, y el valor de x en fun1 será 5. 

Tipo 2. Valor de una enumeración fuera de rango:

Si una enumeración con ámbito se convierte en un tipo integral que es demasiado pequeño para contener su valor, el valor resultante no se especifica. Además, si un entero se convierte en una enumeración y el valor del entero está fuera del rango de los valores de la enumeración, el valor resultante no se especifica.

Ejemplo:

enum Geeks {
    ONE = 1,
    TWO = 2,
    THREE = 3,
};

Geeks s = static_cast<Geeks>(4);

Sin embargo, en el siguiente ejemplo, el comportamiento no está sin especificar, ya que el valor de la fuente está dentro del rango de la enumeración, aunque no es igual a todos los enumeradores:

enum Geeks {
    ONE = 1,
    TWO = 2,
    FOUR = 4,
};
Geeks s = static_cast<Geeks>(3);

Aquí s tendrá el valor 3 y no será igual a UNO, DOS y CUATRO .

A continuación se muestra la ilustración del mismo:

C++

// C++ program to illustrate the value
// of an out-of-range enum:
#include <iostream>
using namespace std;
  
// enum Structure
enum Geeks {
    ONE = 1,
    TWO = 2,
    FOUR = 4,
};
  
// Driver Code
int main()
{
  
    Geeks s = static_cast<Geeks>(3);
  
    // Printing the value of s.
    cout << s;
    return 0;
}
Producción:

3

Tipo 3. Reparto estático desde valor nulo*:

Si un valor void* se convierte en un puntero al tipo de objeto, A*, pero no se alinea correctamente para A, el valor del puntero resultante no se especifica. 

Ejemplo:

// Suppose that alignof(int) is 4
int x = 20;
void* p1 = &x;

// Perform some pointer arithmetic...
void* p2 = static_cast<char*>(p1) + 2;
int* p3 = static_cast<int*>(p2);

El valor de p3 no se especifica porque p2 no puede apuntar a un objeto de tipo int; su valor no es una dirección correctamente alineada.

Escriba 4. Resultado de las conversiones reinterpret_cast:

No se especifican los resultados de un reinterpret_cast de un tipo de puntero de objeto a otro o de un tipo de referencia de objeto a otro.

 Ejemplo:

int x = 42;
char* p = reinterpret_cast<char*>(&x);

Sin embargo, con la mayoría de los compiladores, esto era equivalente a static_cast<char*>(static_cast<void*>(&x)) por lo que el puntero resultante p apuntaba al primer byte de x. Esto se convirtió en el comportamiento estándar en C++11.

C++

// C++ program to illustrate the result
// of reinterpret_cast conversions
#include <iostream>
using namespace std;
  
// Driver Code
int main()
{
  
    int x = 42;
    char* p = reinterpret_cast<char*>(&x);
  
    // Print the value of p
    cout << p;
    return 0;
}
Producción:

*

Tipo 5. Resultado de algunas comparaciones de punteros:

Si se comparan dos punteros utilizando <, >, <= o ≥, el resultado no se especifica en los siguientes casos:

  • Los punteros apuntan a arrays diferentes, es decir, un objeto que no es una array se considera una array de tamaño (1). A continuación se muestra la ilustración del mismo:

    C++

    // C++ program to illustrate that the
    // pointers point into different arrays
    #include <iostream>
    using namespace std;
      
    // Driver Code
    int main()
    {
      
        int x;
        int y;
      
        // unspecified
        const bool b1 = &x < &y;
        int a[10];
      
        // Given True
        const bool b2 = &a[0] < &a[1];
      
        // unspecified
        const bool b3 = &a[0] < &x;
      
        // a + 10 points past the end of array
        const bool b4 = (a + 9) < (a + 10);
      
        cout << b1 << "\n"
             << b2
             << "\n"
             << b3 << "\n"
             << b4;
        return 0;
    }
    Producción:

    1
    1
    0
    1
    
  • Los punteros apuntan al mismo objeto, pero a miembros con diferente control de acceso. A continuación se muestra la implementación del mismo:

    C++

    // C++ program to illustrate that the
    // pointers point into the same object,
    // but to members with different
    // access control
    #include <iostream>
    using namespace std;
      
    // Class A
    class A {
    public:
        int x;
        int y;
      
        // Function returns true if
        // x comes before y
        bool f1() { return &x < &y; }
      
        // unspecified
        bool f2() { return &x < &z; }
    private:
        int z;
    };
      
    // Driver Code
    int main()
    {
      
        // Object of class A
        A a;
      
        // Function Call
        cout << a.f1() << "\n"
             << a.f2();
        return 0;
    }
    Producción:

    1
    1
    

Hay muchos comportamientos no especificados del lenguaje C y algunos de ellos son:

  1. La forma y el momento de la inicialización estática.
  2. El estado de terminación devuelto al entorno hospedado si el tipo de retorno de main no es compatible con int.
  3. El valor de los bytes de relleno al ordenar valores en estructuras o uniones.
  4. El orden en el que se evalúan las subexpresiones y el orden en el que se producen los efectos secundarios, excepto lo especificado para la llamada de función ( ), &&, ||, ?: y el operador de coma.
  5. el diseño de almacenamiento para parámetros de función en el marco de pila.
  6. Los resultados del redondeo cuando el valor está fuera de límite.

Publicación traducida automáticamente

Artículo escrito por poulami21ghosh y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *