Onde C não é um subconjunto de C ++? [fechadas]

116

Eu li em muitos livros que C é um subconjunto de C ++.

Alguns livros dizem que C é um subconjunto de C ++, exceto pelos pequenos detalhes .

Quais são alguns casos em que o código será compilado em C, mas não em C ++?

n00ki3
fonte

Respostas:

135

Se você comparar C89com C++então aqui estão algumas coisas

Sem definições provisórias em C ++

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

int [] e int [N] não compatíveis (nenhum tipo compatível em C ++)

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

Sem estilo de definição de função K&R

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

A estrutura aninhada tem escopo de classe em C ++

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

Sem padrão int

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

C99 adiciona muitos outros casos

Nenhum tratamento especial de especificadores de declaração em dimensões de matriz de parâmetros

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

Sem matrizes de comprimento variável

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

Nenhum membro de matriz flexível

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

Nenhum qualificador de restrição para ajudar na análise de aliasing

// ill-formed: two names for one parameter?
void copy(int *restrict src, int *restrict dst);
Johannes Schaub - litb
fonte
@mehrdad, obrigado. oO não sabia que já era necessário criar uma variável ao declarar uma estrutura aninhada em C. Fixo.
Johannes Schaub - litb
3
Há outro (inútil) de C89 para C ++: typedef;é um TU legal em C, mas não em C ++.
Flexo
Observe que auto a;é válido na revisão padrão C ++ mais recente.
fuz
3
@FUZxxl realmente? Qual será o tipo deduzido de a?
Johannes Schaub - litb
3
@FUZxxl ah obrigado. Portanto, auto x;não é válido na revisão mais recente, mas auto x = 0;é , por exemplo . Fiquei um pouco chocado no início :)
Johannes Schaub - litb
50

Em C, sizeof('a')é igual a sizeof(int).

Em C ++, sizeof('a')é igual a sizeof(char).

Naveen
fonte
46
Isso pode ser simplificado para: Em C, 'a'é um int. Em C ++, 'a'é a char.
pmg
38

C ++ também tem novas palavras-chave. O seguinte é um código C válido, mas não compilará em C ++:

int class = 1;
int private = 2;
int public = 3;
int virtual = 4;
Graeme Perrow
fonte
1
é verdade, mas é exatamente isso que significa subconjunto.
yeyeyerman
20
@yeyeyerman: Não. Para ser um subconjunto, todo código C teria que ser C ++ válido também. O código neste exemplo é C válido, mas não C ++.
jalf
24
Não, se C fosse um subconjunto estrito de C ++, então todo programa C seria um programa C ++ válido, mas isso não é verdade. A questão é por que isso não é verdade, e este é um exemplo disso.
Graeme Perrow
Ha! Não pensei sobre este!
Gab Royer
20

Existem muitas coisas. Apenas um exemplo simples (deve ser o suficiente para provar que C não é um subconjunto adequado de C ++):

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

deve compilar em C, mas não em C ++.

Mehrdad Afshari
fonte
3
C ++ deve exigir uma conversão explícita para int*.
Mehrdad Afshari
8
Resposta longa: malloc retorna void *, que em C pode ser atribuído a qualquer tipo de ponteiro, e C ++ não pode ser atribuído a nenhum outro tipo de ponteiro.
Daniel Earwicker
5
Imagist: um compilador C, conforme definido pelo padrão ANSI C89, não deve reclamar.
Mehrdad Afshari
7
É legal C. O elenco é desnecessário, é possível errar e encobre uma falha ao incluir <stdlib.h>. Considero a declaração de Mehrdad a maneira certa de escrevê-la em C.
David Thornley
16
@Imagist: Normalmente ouço o contrário dos programadores C. Eles consideram um estilo ruim adicionar o elenco, pois pode esconder insetos. O bom código C não usa elenco.
jalf
16

Em C ++, se você declarar uma struct, unionou enum, seu nome é imediatamente acessível, sem quaisquer qualificadores:

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

Em C, isso não funcionará, porque os tipos assim declarados vivem em seus próprios namespaces distintos. Portanto, você deve escrever:

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

Observe a presença de structlá na segunda linha. Você deve fazer o mesmo para unione enum(usando suas respectivas palavras-chave), ou use o typedeftruque:

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

Consequentemente, você pode ter vários tipos de tipos diferentes com o mesmo nome em C, uma vez que você pode desambiguar:

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

struct foo x;
foo y;

Em C ++, entretanto, embora você possa prefixar um structnome com palavra-chave structsempre que fizer referência a ele, os namespaces são mesclados e, portanto, o fragmento C acima não é válido. Por outro lado, C ++ especificamente faz uma exceção para permitir que um tipo e um typedef para esse tipo tenham o mesmo nome (obviamente sem efeito), para permitir o uso de typedeftruque inalterado de C.

Pavel Minaev
fonte
1
Seu último exemplo é C inválido: As três tags ( struct, unione enum) compartilham o mesmo namespace. Um exemplo melhor seriastruct foo { ... }; typedef enum { ... } foo;
schot
@schot: é claro que você está certo, obrigado pela correção. Atualizada.
Pavel Minaev
8

Isso também depende da variedade de C que você está usando. Stroustrup tornou o C ++ o mais compatível possível, e não mais compatível, com os padrões ANSI de 1989 e ISO de 1990, e a versão de 1995 não mudou nada. O comitê C foi em uma direção um pouco diferente com o padrão de 1999, e o comitê C ++ mudou o próximo padrão C ++ (provavelmente no próximo ano ou depois) para se conformar com algumas das mudanças.

Stroustrup lista incompatibilidades com C90 / C95 no Apêndice B.2 de "The C ++ Programming Language", Edição Especial (que é a 3ª edição com algum material adicionado):

'a'é um intem C, umchar em C ++.

O tamanho de um enum é int em C, não necessariamente em C ++.

C ++ tem // comentários até o fim da linha, C não (embora seja uma extensão comum).

Em C ++, uma struct foo {definição é fooinserida no espaço de nomes global, enquanto em C ela teria que ser referida como struct foo. Isso permite que uma structdefinição sombreie um nome em um escopo externo e tem algumas outras consequências. Além disso, C permite um escopo maior parastruct definições e as permite em declarações de tipo de retorno e tipo de argumento.

C ++ é mais complicado com os tipos em geral. Ele não permite que um inteiro seja atribuído a um enume os void *objetos não podem ser atribuídos a outros tipos de ponteiro sem uma conversão. Em C, é possível fornecer um inicializador overlarge (char name[5] = "David" onde C descartará o caractere nulo final).

O C89 permite implícito intem muitos contextos, e o C ++ não. Isso significa que todas as funções devem ser declaradas em C ++, enquanto em C89 era freqüentemente possível assumir inttudo o que é aplicável na declaração da função.

Em C, é possível pular de fora de um bloco para dentro usando uma instrução rotulada. Em C ++, isso não é permitido se pular uma inicialização.

C é mais liberal na vinculação externa. Em C, uma constvariável global é implicitamente extern, e isso não é verdade em C ++. C permite que um objeto de dados global seja declarado várias vezes sem umextern , mas isso não é verdade em C ++.

Muitas palavras-chave C ++ não são palavras-chave em C, ou são #defined em cabeçalhos C padrão.

Existem também alguns recursos mais antigos do C que não são mais considerados um bom estilo. Em C, você pode declarar uma função com as definições de argumento após a lista de argumentos. Em C, uma declaração como int foo()significa que foo()pode receber qualquer número de qualquer tipo de argumento, enquanto em C ++ é equivalente a int foo(void).

Isso parece cobrir tudo, desde Stroustrup.

David Thornley
fonte
Não vamos esquecer o fato de que, em C, você deve declarar variáveis ​​no início de um escopo (ou seja, imediatamente após uma chave de abertura), enquanto C ++ permite declarações de variáveis ​​em qualquer lugar.
RobH
4
No entanto, isso é algo que C ++ pode fazer que C não pode. Acho que estamos vendo coisas que você pode fazer em C, mas não em C ++.
David Thornley
2
@RobH: Isso é verdade para o C89, mas não para o C99.
Jamesdlin
6

Se você usar o gcc, pode usar o aviso -Wc++-compatpara dar-lhe avisos sobre o código C que é duvidoso em C ++ de alguma forma. Atualmente é usado no próprio gcc e ficou muito melhor recentemente (talvez tente uma versão noturna para obter o melhor que puder).

(Isso não responde estritamente à pergunta, mas as pessoas podem gostar).

Paul Biggar
fonte
1
Pensei que nunca
votaria a favor de
4

A maior diferença, creio, é que este é um arquivo-fonte C válido:

int main()
{
    foo();
}

Observe que eu não declarei foo lugar nenhum.

Além das diferenças de linguagem, C ++ também faz algumas alterações na biblioteca que herdou de C, por exemplo, algumas funções retornam em const char *vez de char *.

Daniel Earwicker
fonte
Certo, os protótipos não são necessários em C, mas geralmente é considerado uma prática ruim não usá-los.
Robert Gamble
1
Você deve fazer s,C,C89,e observar que é um arquivo de origem C99 inválido.
Johannes Schaub - litb
É inválido ou apenas obsoleto no C99?
jalf
2
@jalf o rascunho do C99 documenta as mudanças no C89 e inclui "remover int implícito" e "remover declaração de função implícita".
Johannes Schaub - litb
4
#include <stdio.h>

int new (int n) {
    return n/2;
}

int main(void) {
    printf("%d\n", new(10));
    return 0;
}

Consulte também a entrada C ++ FAQ .

Sinan Ünür
fonte
2

Várias das respostas aqui cobrem diferenças de sintaxe que fariam com que os compiladores C ++ falhem no código-fonte C89 (ou C99). No entanto, existem algumas diferenças sutis de idioma que são legais em ambos os idiomas, mas que produziriam um comportamento diferente. A sizeof (char)diferença que Naveen mencionou é um exemplo, mas escrever um programa que irá imprimir "C" se compilado como um programa C (ANSI) e "C ++" se compilado como um programa C ++ lista alguns outros.

Jamesdlin
fonte
-2

Os compiladores C geralmente permitem um pequeno corte que o C ++ não permite. C ++ é muito mais estrito do que C. E geralmente, algumas dessas diferenças dependem do compilador. g ++ permite algumas coisas que o compilador Intel C ++ não permite, por exemplo. Mesmo o código C bem escrito não compilará com um compilador C ++ moderno.

xcramps
fonte
-2

Você não pode comparar idiomas apenas pela sintaxe. Se você fizer isso, talvez possa ver C como um subconjunto de C ++. Na minha opinião, o fato de C ++ ser OO (e C não) é suficiente para dizer que C e C ++ são linguagens diferentes.

Fnurglewitz
fonte
2
Errado. C ++ não é apenas OO. Você poderia pensar em C ++ algo como "C ++ = C + OO + programação genérica + bônus". Em outras palavras, "C & C ++ ~ = C" onde ~ = significa quase igual.
paercebal