c++ codigo linguistico - ¿Puede el código que es válido en C y C ++ producir un comportamiento diferente cuando se compila en cada idioma?





9 Answers

Este es un ejemplo que aprovecha la diferencia entre las llamadas a funciones y las declaraciones de objetos en C y C ++, así como el hecho de que C90 permite la llamada de funciones no declaradas:

#include <stdio.h>

struct f { int x; };

int main() {
    f();
}

int f() {
    return printf("hello");
}

En C ++ esto no imprimirá nada porque se crea y destruye una f temporal, pero en C90 imprime hello porque las funciones se pueden llamar sin haber sido declaradas.

En caso de que se esté preguntando si el nombre f se usa dos veces, los estándares C y C ++ lo permiten explícitamente, y para hacer que un objeto tenga que decir la struct f a la ambigüedad si desea la estructura, o deje de struct la struct si desea que la función .

ejemplos no codigos

C y C ++ tienen muchas diferencias, y no todos los códigos C válidos son códigos C ++ válidos.
(Por "válido" me refiero a un código estándar con comportamiento definido, es decir, no específico de la implementación / indefinido / etc.)

¿Hay algún escenario en el que un fragmento de código válido en C y C ++ produzca un comportamiento diferente cuando se compila con un compilador estándar en cada idioma?

Para hacer una comparación razonable / útil (estoy tratando de aprender algo práctico útil, no tratar de encontrar lagunas evidentes en la pregunta), asumamos:

  • Nada relacionado con el preprocesador (lo que significa que no hay #ifdef __cplusplus con #ifdef __cplusplus , pragmas, etc.)
  • Cualquier cosa definida por la implementación es la misma en ambos idiomas (por ejemplo, límites numéricos, etc.)
  • Estamos comparando versiones razonablemente recientes de cada estándar (por ejemplo, C ++ 98 y C90 o posterior)
    Si las versiones son importantes, mencione qué versiones de cada una producen un comportamiento diferente.



C90 vs. C ++ 11 ( int vs. double ):

#include <stdio.h>

int main()
{
  auto j = 1.5;
  printf("%d", (int)sizeof(j));
  return 0;
}

En C auto significa variable local. En C90 está bien omitir el tipo de variable o función. El valor predeterminado es int . En C ++ 11 auto significa algo completamente diferente, le dice al compilador que deduzca el tipo de variable del valor usado para inicializarlo.




Según el estándar C ++ 11:

a. El operador de coma realiza la conversión de valor a valor en C pero no en C ++:

   char arr[100];
   int s = sizeof(0, arr);       // The comma operator is used.

En C ++, el valor de esta expresión será 100 y en C será sizeof(char*) .

segundo. En C ++ el tipo de enumerador es su enumeración. En C el tipo de enumerador es int.

   enum E { a, b, c };
   sizeof(a) == sizeof(int);     // In C
   sizeof(a) == sizeof(E);       // In C++

Esto significa que sizeof(int) puede no ser igual a sizeof(E) .

do. En C ++, una función declarada con una lista de parámetros vacía no toma argumentos. En C, la lista de parámetros vacía significa que se desconoce el número y el tipo de función params.

   int f();           // int f(void) in C++
                      // int f(*unknown*) in C



Otra trampa sizeof : expresiones booleanas.

#include <stdio.h>
int main() {
    printf("%d\n", (int)sizeof !0);
}

Es igual a sizeof(int) en C, porque la expresión es de tipo int , pero normalmente es 1 en C ++ (aunque no es necesario que lo sea). En la práctica son casi siempre diferentes.




Una castaña antigua que depende del compilador de C, que no reconoce los comentarios de fin de línea de C ++ ...

...
int a = 4 //* */ 2
        +2;
printf("%i\n",a);
...



Otro listado por el estándar de C ++:

#include <stdio.h>

int x[1];
int main(void) {
    struct x { int a[2]; };
    /* size of the array in C */
    /* size of the struct in C++ */
    printf("%d\n", (int)sizeof(x)); 
}



struct abort
{
    int x;
};

int main()
{
    abort();
    return 0;
}

Vuelve con el código de salida de 0 en C ++ o 3 en C.

Este truco probablemente podría usarse para hacer algo más interesante, pero no se me ocurrió una buena manera de crear un constructor que fuera aceptable para C. Intenté hacer un ejemplo igualmente aburrido con el constructor de copia, que permitiría una discusión. ser aprobado, aunque de una manera bastante no portátil:

struct exit
{
    int x;
};

int main()
{
    struct exit code;
    code.x=1;

    exit(code);

    return 0;
}

VC ++ 2005 se negó a compilar eso en modo C ++, sin embargo, quejándose de cómo se redefinió el "código de salida". (Creo que este es un error del compilador, a menos que de repente haya olvidado cómo programar). Salió con un código de salida de proceso de 1 cuando se compila como C.




No olvide la distinción entre los espacios de nombres globales de C y C ++. Supongamos que tienes un foo.cpp

#include <cstdio>

void foo(int r)
{
  printf("I am C++\n");
}

y un foo2.c

#include <stdio.h>

void foo(int r)
{
  printf("I am C\n");
}

Ahora suponga que tiene un main.c y main.cpp que se ven así:

extern void foo(int);

int main(void)
{
  foo(1);
  return 0;
}

Cuando se compila como C ++, usará el símbolo en el espacio de nombres global de C ++; en C utilizará la C one:

$ diff main.cpp main.c
$ gcc -o test main.cpp foo.cpp foo2.c
$ ./test 
I am C++
$ gcc -o test main.c foo.cpp foo2.c
$ ./test 
I am C



Las estructuras vacías tienen tamaño 0 en C y 1 en C ++:

#include <stdio.h>

typedef struct {} Foo;

int main()
{
    printf("%zd\n", sizeof(Foo));
    return 0;
}





Related


Tags

c++   c