tipos paralinguistico linguisticos linguistico ejemplos codigos codigo c++ c

c++ - linguisticos - codigo paralinguistico



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

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.

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.

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 .


Este programa imprime 1 en C ++ y 0 en C:

#include <stdio.h> #include <stdlib.h> int main(void) { int d = (int)(abs(0.6) + 0.5); printf("%d", d); return 0; }

Esto sucede porque hay double abs(double) sobrecarga de double abs(double) en C ++, por lo que abs(0.6) devuelve 0.6 mientras que en C devuelve 0 debido a la conversión implícita de doble a int antes de invocar int abs(int) . En C, tienes que usar fabs para trabajar con double .


Esto se refiere a los valores de l y rvalues ​​en C y C ++.

En el lenguaje de programación C, tanto el pre-incremento como los operadores post-incremento devuelven valores, no valores. Esto significa que no pueden estar en el lado izquierdo del operador de asignación = . Ambas declaraciones darán un error de compilación en C:

int a = 5; a++ = 2; /* error: lvalue required as left operand of assignment */ ++a = 2; /* error: lvalue required as left operand of assignment */

En C ++, sin embargo, el operador de preincremento devuelve un lvalue, mientras que el operador de postincremento devuelve un rvalue. ¡Significa que una expresión con el operador de preincremento se puede colocar en el lado izquierdo del operador de asignación = !

int a = 5; a++ = 2; // error: lvalue required as left operand of assignment ++a = 2; // No error: a gets assigned to 2!

Ahora por qué esto es así? El incremento posterior incrementa la variable, y devuelve la variable como estaba antes de que ocurriera el incremento. Esto es en realidad sólo un valor. El valor anterior de la variable a se copia en un registro como temporal, y luego se incrementa a. Pero el valor anterior de a es devuelto por la expresión, es un valor de r. Ya no representa el contenido actual de la variable.

El pre-incremento primero incrementa la variable, y luego retorna la variable como se hizo después de que ocurrió el incremento. En este caso, no necesitamos almacenar el valor antiguo de la variable en un registro temporal. Simplemente recuperamos el nuevo valor de la variable después de que se haya incrementado. Entonces, el pre-incremento devuelve un lvalor, retorna la variable a sí misma. Podemos usar asignar este valor límico a otra cosa, es como la siguiente declaración. Esta es una conversión implícita de lvalue en rvalue.

int x = a; int x = ++a;

Dado que el pre-incremento devuelve un lvalor, también podemos asignarle algo. Las siguientes dos afirmaciones son idénticas. En la segunda asignación, primero se incrementa a, luego se sobrescribe su nuevo valor con 2.

int a; a = 2; ++a = 2; // Valid in 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; }


Las funciones en línea en C están predeterminadas para el alcance externo donde las funciones en C ++ no lo hacen.

Compilar los dos archivos siguientes juntos imprimiría "Estoy en línea" en el caso de GNU C, pero nada para C ++.

Archivo 1

#include <stdio.h> struct fun{}; int main() { fun(); // In C, this calls the inline function from file 2 where as in C++ // this would create a variable of struct fun return 0; }

Archivo 2

#include <stdio.h> inline void fun(void) { printf("I am inline/n"); }

Además, C ++ trata de forma implícita cualquier const global como static menos que se declare explícitamente extern , a diferencia de C en la que extern es el valor predeterminado.


Lo siguiente, válido en C y C ++, dará como resultado (lo más probable) resultados diferentes en i en C y C ++:

int i = sizeof(''a'');

Consulte Tamaño del carácter (''a'') en C / C ++ para obtener una explicación de la diferencia.

Otro de este artículo :

#include <stdio.h> int sz = 80; int main(void) { struct sz { char c; }; int val = sizeof(sz); // sizeof(int) in C, // sizeof(struct sz) in C++ printf("%d/n", val); return 0; }


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


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.


Otro ejemplo que no he visto mencionado aún, este destaca una diferencia de preprocesador:

#include <stdio.h> int main() { #if true printf("true!/n"); #else printf("false!/n"); #endif return 0; }

Esto imprime "falso" en C y "verdadero" en C ++: en C, cualquier macro indefinida se evalúa como 0. En C ++, hay 1 excepción: "verdadero" se evalúa como 1.


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)); }


Para C ++ frente a C90, hay al menos una forma de obtener un comportamiento diferente que no está definido por la implementación. C90 no tiene comentarios de una sola línea. Con un poco de cuidado, podemos usar eso para crear una expresión con resultados completamente diferentes en C90 y en C ++.

int a = 10 //* comment */ 2 + 3;

En C ++, todo desde el // hasta el final de la línea es un comentario, por lo que esto funciona como:

int a = 10 + 3;

Como C90 no tiene comentarios de una sola línea, solo el /* comment */ es un comentario. El primero / y el 2 son partes de la inicialización, por lo que se trata de:

int a = 10 / 2 + 3;

Por lo tanto, un compilador de C ++ correcto dará 13, pero un compilador de C correcto 8. Por supuesto, elegí números arbitrarios aquí. Puedes usar otros números como mejor te parezca.


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


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); ...


El lenguaje de programación C ++ (3ª edición) ofrece tres ejemplos:

  1. sizeof (''a''), como lo mencionó @Adam Rosenfield;

  2. // comentarios que se utilizan para crear código oculto:

    int f(int a, int b) { return a //* blah */ b ; }

  3. Estructuras, etc. que ocultan cosas fuera de los ámbitos, como en su ejemplo.


#include <stdio.h> int main(void) { printf("%d/n", (int)sizeof(''a'')); return 0; }

En C, esto imprime cualquiera que sea el valor de sizeof(int) en el sistema actual, que suele ser 4 en la mayoría de los sistemas que se usan comúnmente en la actualidad.

En C ++, esto debe imprimirse 1.


#include <stdio.h> struct A { double a[32]; }; int main() { struct B { struct A { short a, b; } a; }; printf("%d/n", sizeof(struct A)); return 0; }

Este programa imprime 128 ( 32 * sizeof(double) ) cuando se compila con un compilador de C ++ y 4 cuando se compila con un compilador de C.

Esto se debe a que C no tiene la noción de resolución de alcance. En C, las estructuras contenidas en otras estructuras se ponen dentro del alcance de la estructura exterior.


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.