¿Dónde no es C un subconjunto de C ++? [cerrado]

116

Leí en muchos libros que C es un subconjunto de C ++.

Algunos libros dicen que C es un subconjunto de C ++, excepto por los pequeños detalles .

¿Cuáles son algunos casos en los que el código se compilará en C, pero no en C ++?

n00ki3
fuente

Respuestas:

135

Si se compara C89con C++, aquí hay un par de cosas.

Sin definiciones provisionales en C ++

int n;
int n; // ill-formed: n already defined

int [] e int [N] no son compatibles (no hay tipos compatibles en C ++)

int a[1];
int (*ap)[] = &a; // ill-formed: a does not have type int[]

Sin estilo de definición de función K&R

int b(a) int a; { } // ill-formed: grammar error

La estructura anidada tiene un alcance de clase en C ++

struct A { struct B { int a; } b; int c; };
struct B b; // ill-formed: b has incomplete type (*not* A::B)

Sin int predeterminado

auto a; // ill-formed: type-specifier missing

C99 agrega muchos otros casos

Sin manejo especial de especificadores de declaración en dimensiones de matriz de parámetros

// ill-formed: invalid syntax
void f(int p[static 100]) { }

Sin matrices de longitud variable

// ill-formed: n is not a constant expression
int n = 1;
int an[n];

Ningún miembro de matriz flexible

// ill-formed: fam has incomplete type
struct A { int a; int fam[]; }; 

Sin calificador de restricción para ayudar al análisis de aliasing

// ill-formed: two names for one parameter?
void copy(int *restrict src, int *restrict dst);
Johannes Schaub - litb
fuente
@mehrdad, gracias. oO no sabía que uno ya tenía que crear una variable al declarar una estructura anidada en C. Fijo.
Johannes Schaub - litb
3
Hay otro (inútil) de C89 a C ++: typedef;es una TU legal en C, pero no en C ++.
Flexo
Tenga en cuenta que auto a;es válido en la revisión estándar más reciente de C ++.
fuz
3
@FUZxxl ¿de verdad? ¿Cuál será el tipo de deducido a?
Johannes Schaub - litb
3
@FUZxxl ah gracias. Entonces auto x;no es válido en la revisión más reciente, pero por ejemplo lo auto x = 0;es. Al principio estaba un poco sorprendido :)
Johannes Schaub - litb
50

En C, sizeof('a')es igual asizeof(int) .

En C ++, sizeof('a')es igual a sizeof(char).

Naveen
fuente
46
Eso se puede simplificar a: En C, 'a'es un int. En C ++, 'a'es un char.
pmg
38

C ++ también tiene nuevas palabras clave. El siguiente es un código C válido, pero no se compilará en C ++:

int class = 1;
int private = 2;
int public = 3;
int virtual = 4;
Graeme Perrow
fuente
1
es cierto, pero eso es exactamente lo que significa subconjunto.
yeyeyerman
20
@yeyeyerman: No. Para que sea un subconjunto, todo el código C debería ser C ++ válido también. El código de este ejemplo es C válido pero no C ++.
jalf
24
No, si C fuera un subconjunto estricto de C ++, entonces cada programa C sería un programa C ++ válido, pero eso no es cierto. La pregunta es por qué no es cierto, y este es un ejemplo de por qué.
Graeme Perrow
¡Decir ah! ¡No pensé en este!
Gab Royer
20

Hay muchas cosas. Solo un ejemplo simple (debería ser suficiente para demostrar que C no es un subconjunto adecuado de C ++):

int* test = malloc(100 * sizeof(int));

debería compilarse en C pero no en C ++.

Mehrdad Afshari
fuente
3
C ++ debería requerir una conversión explícita a int*.
Mehrdad Afshari
8
Respuesta larga: devuelve malloc void *, que en C se puede asignar a cualquier tipo de puntero, y C ++ no se puede asignar a ningún otro tipo de puntero.
Daniel Earwicker
5
Imagist: un compilador de C, según lo definido por el estándar ANSI C89, no debería quejarse.
Mehrdad Afshari
7
Es legal C. El elenco es innecesario, es posible equivocarse y encubre una falla al incluir <stdlib.h>. Considero que la declaración de Mehrdad es la forma correcta de escribirla en C.
David Thornley
16
@Imagist: Normalmente escucho lo contrario de los programadores de C. Consideran que es un estilo deficiente agregar el yeso, ya que puede ocultar errores. El buen código C no usa el molde.
jalf
16

En C ++, si declara una struct, uniono enum, su nombre es inmediatamente accesible sin ningún tipo de calificativos:

struct foo { ... };
foo x; // declare variable

En C, esto no funcionará, porque los tipos así declarados viven en sus propios espacios de nombres distintos. Por tanto, tienes que escribir:

struct foo { ... };
struct foo x; // declare variable

Note la presencia de structallí en la segunda línea. Tienes que hacer lo mismo para uniony enum(usando sus respectivas palabras clave), o usar el typedeftruco:

typedef struct { ... } foo;
foo x; // declare variable

En consecuencia, puede tener varios tipos de diferentes tipos con el mismo nombre en C, ya que puede eliminar la ambigüedad:

struct foo { ... };
typedef enum { ... } foo;

struct foo x;
foo y;

En C ++, sin embargo, aunque puede prefijar un structnombre con una palabra clave structsiempre que haga referencia a él, los espacios de nombres se combinan, por lo que el fragmento de C anterior no es válido. Por otro lado, C ++ específicamente hace una excepción para permitir que un tipo y un typedef para ese tipo tengan el mismo nombre (obviamente sin efecto), para permitir el uso de typedeftrucos sin cambios de C.

Pavel Minaev
fuente
1
Su último ejemplo no es válido C: las tres etiquetas ( struct, uniony enum) comparten el mismo espacio de nombres. Un mejor ejemplo seríastruct foo { ... }; typedef enum { ... } foo;
schot
@schot: por supuesto que tiene razón, gracias por la corrección. Actualizado.
Pavel Minaev
8

Esto también depende de la variedad de C que esté utilizando. Stroustrup hizo C ++ tan compatible como pudo, y no más compatible, con las normas ANSI de 1989 e ISO de 1990, y la versión de 1995 no cambió nada. El comité de C tomó una dirección algo diferente con el estándar de 1999, y el comité de C ++ ha cambiado el siguiente estándar de C ++ (probablemente el próximo año más o menos) para ajustarse a algunos de los cambios.

Stroustrup enumera las incompatibilidades con C90 / C95 en el Apéndice B.2 de "El lenguaje de programación C ++", Edición especial (que es la tercera edición con algo de material agregado):

'a'es un inten C, un charen C ++.

El tamaño de una enumeración está inten C, no necesariamente en C ++.

C ++ tiene //comentarios hasta el final de la línea, C no (aunque es una extensión común).

En C ++, una struct foo {definición se coloca fooen el espacio de nombres global, mientras que en C tendría que denominarse struct foo. Esto permite que una structdefinición oculte un nombre en un ámbito externo y tiene algunas otras consecuencias. Además, C permite un mayor alcance para las structdefiniciones y las permite en declaraciones de tipo de retorno y tipo de argumento.

C ++ es más exigente con los tipos en general. No permitirá que se asigne un número entero a un enum, y los void *objetos no se pueden asignar a otros tipos de puntero sin una conversión. En C, es posible proporcionar un inicializador demasiado grande (char name[5] = "David" donde C descartará el carácter nulo final).

C89 se permite implícitamente inten muchos contextos y C ++ no. Esto significa que todas las funciones deben declararse en C ++, mientras que en C89 a menudo era posible asumir inttodo lo aplicable en la declaración de función.

En C, es posible saltar del exterior de un bloque al interior utilizando una declaración etiquetada. En C ++, esto no está permitido si se salta una inicialización.

C es más liberal en el enlace externo. En C, una constvariable global es implícita extern, y eso no es cierto en C ++. C permite que un objeto de datos global se declare varias veces sin unextern , pero eso no es cierto en C ++.

Muchas palabras clave de C ++ no son palabras clave en C o están #defined en encabezados C estándar.

También hay algunas características antiguas de C que ya no se consideran de buen estilo. En C, puede declarar una función con las definiciones de los argumentos después de la lista de argumentos. En C, una declaración como int foo()significa que foo()puede tomar cualquier número de cualquier tipo de argumentos, mientras que en C ++ es equivalente a int foo(void).

Eso parece cubrir todo, desde Stroustrup.

David Thornley
fuente
No olvidemos el hecho de que, en C, debe declarar variables al comienzo de un ámbito (es decir, inmediatamente después de una llave de apertura), mientras que C ++ permite declaraciones de variables en cualquier lugar.
RobH
4
Sin embargo, eso es algo que C ++ puede hacer y C no puede. Creo que estamos viendo cosas que puede hacer en C pero no en C ++.
David Thornley
2
@RobH: Eso es cierto para C89 pero no para C99.
jamesdlin
6

Si usa gcc, puede usar la advertencia -Wc++-compat para darle advertencias sobre el código C que es dudoso en C ++ de alguna manera. Actualmente se utiliza en gcc y ha mejorado mucho recientemente (tal vez pruebe una versión nocturna para obtener lo mejor que pueda).

(Esto no responde estrictamente a la pregunta, pero a la gente le puede gustar).

Paul Biggar
fuente
1
Pensé que nunca votaría a favor de una respuesta sin respuesta
eharo2
4

Creo que la mayor diferencia es que este es un archivo fuente C válido:

int main()
{
    foo();
}

Tenga en cuenta que no he declarado en fooningún lado.

Aparte de las diferencias de idioma, C ++ también realiza algunos cambios en la biblioteca que heredó de C, por ejemplo, algunas funciones devuelven en const char *lugar de char *.

Daniel Earwicker
fuente
Correcto, los prototipos no son necesarios en C, pero generalmente se considera una mala práctica no usarlos.
Robert Gamble
1
Debe hacerlo s,C,C89,y tenga en cuenta que es un archivo fuente C99 no válido.
Johannes Schaub - litb
Sin embargo, ¿es inválido o simplemente obsoleto en C99?
jalf
2
@jalf el borrador de C99 documenta los cambios a C89 e incluye tanto "eliminar int implícita" y "eliminar declaración de función implícita".
Johannes Schaub - litb
2

Algunas de las respuestas aquí cubren diferencias de sintaxis que harían que los compiladores de C ++ fallaran en el código fuente C89 (o C99). Sin embargo, existen algunas diferencias sutiles de idioma que son legales en ambos idiomas pero que producirían un comportamiento diferente. La sizeof (char)diferencia que mencionó Naveen es un ejemplo, pero escriba un programa que imprima "C" si se compila como un programa (ANSI) C, y "C ++" si se compila como un programa C ++ enumera algunos otros.

jamesdlin
fuente
-2

Los compiladores de C generalmente permitieron un pequeño corte de esquina que C ++ no permite. C ++ es mucho más estricto que C. Y, en general, algunas de estas diferencias dependen del compilador. g ++ permite algunas cosas que el compilador Intel C ++ no permite, por ejemplo. Incluso el código C bastante bien escrito no se compilará con un compilador C ++ moderno.

xcramps
fuente
-2

No puede comparar idiomas solo por sintaxis. Si lo hace, tal vez pueda ver a C como un subconjunto de C ++. En mi opinión, el hecho de que C ++ sea OO (y C no) es suficiente para decir que C y C ++ son lenguajes diferentes.

Fnurglewitz
fuente
2
Incorrecto. C ++ no es solo OO. Se podría pensar en C ++ como "C ++ = C + OO + programación genérica + bonificaciones". Para decirlo de otra manera, "C & C ++ ~ = C" donde ~ = significa casi igual.
paercebal