Dov’è C non un sottoinsieme di C ++?

Ho letto in molti libri che C è un sottoinsieme di C ++.

Alcuni libri dicono che C è un sottoinsieme di C ++, fatta eccezione per i piccoli dettagli .

Quali sono alcuni casi in cui il codice verrà compilato in C, ma non in C ++?

Se confronti C89 con C++ ecco un paio di cose

Nessuna definizione provvisoria in C ++

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

int [] e int [N] non compatibili (nessun tipo compatibile in C ++)

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

Nessuno stile di definizione delle funzioni di K & R

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

La struttura annidata ha scope di class in C ++

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

Nessun valore predefinito int

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

C99 aggiunge molti altri casi

Nessuna gestione speciale degli specificatori di dichiarazione nelle dimensioni di array dei parametri

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

Nessun array di lunghezza variabile

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

Nessun membro di array flessibile

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

Nessun qualificatore restrittivo per aiutare l’analisi di aliasing

 // ill-formsd: two names for one parameter? void copy(int *restrict src, int *restrict dst); 

In C, sizeof('a') è uguale a sizeof(int) .

In C ++, sizeof('a') è uguale a sizeof(char) .

Anche il C ++ ha nuove parole chiave. Quanto segue è un codice C valido ma non verrà compilato in C ++:

 int class = 1; int private = 2; int public = 3; int virtual = 4; 

Ci sono molte cose Un semplice esempio (dovrebbe essere sufficiente per dimostrare che C non è un sottoinsieme appropriato di C ++):

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

dovrebbe compilare in C ma non in C ++.

In C ++, se dichiari una struct , union o enum , il suo nome è immediatamente accessibile senza qualificatori:

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

In C, questo non funzionerà, perché i tipi così dichiarati vivono nei propri spazi dei nomi distinti. Quindi, devi scrivere:

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

Notare la presenza di struct lì sulla seconda riga. Devi fare lo stesso per union ed enum (usando le rispettive parole chiave), o usare il trucco typedef :

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

Di conseguenza, puoi avere diversi tipi di diversi tipi chiamati lo stesso in C, dato che puoi disambiguare:

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

In C ++, tuttavia, mentre puoi prefisso un nome di struct con struct parole chiave ogni volta che fai riferimento a esso, gli spazi dei nomi vengono uniti e quindi il cnippet C sopra non è valido. D’altra parte, C ++ fa un’eccezione specifica per consentire a un tipo e un typedef di avere lo stesso nome (ovviamente senza alcun effetto), per consentire l’uso del trucco typedef invariato da C.

Ciò dipende anche dalla varietà di C che stai utilizzando. Stroustrup ha reso C ++ il più compatibile ansible e non più compatibile con gli standard ANSI e 1990 ISO del 1989 e la versione 1995 non ha cambiato nulla. Il comitato C è andato in una direzione un po ‘diversa con lo standard del 1999, e il comitato C ++ ha cambiato il prossimo standard C ++ (probabilmente il prossimo anno o giù di lì) per conformarsi ad alcuni dei cambiamenti.

Stroustrup elenca incompatibilità con C90 / C95 nell’Appendice B.2 di “The C ++ Programming Language”, Special Edition (che è una terza edizione con materiale aggiunto):

'a' è un int in C, un char in C ++.

La dimensione di un enum è int in C, non necessariamente in C ++.

C ++ ha // commenti alla fine della riga, C no (sebbene sia un’estensione comune).

In C ++, una struct foo { definizione mette foo nello spazio dei nomi globale, mentre in C dovrebbe essere indicato come struct foo . Ciò consente a una definizione di struct di ombreggiare un nome in un ambito esterno e ha alcune altre conseguenze. Inoltre, C consente un ambito più ampio per le definizioni di struct e le consente di restituire dichiarazioni di tipo type e argument.

Il C ++ è più fussivo sui tipi in generale. Non consente di assegnare un intero a un enum e gli oggetti void * non possono essere assegnati ad altri tipi di puntatore senza cast. In C, è ansible fornire un inizializzatore di tipo overlarge ( char name[5] = "David" dove C eliminerà il carattere null finale).

C89 ha permesso l’ int implicito in molti contesti, e il C ++ no. Ciò significa che tutte le funzioni devono essere dichiarate in C ++, mentre in C89 è stato spesso ansible ottenere con l’assunzione di int per tutto ciò che è applicabile nella dichiarazione di funzione.

In C, è ansible saltare dall’esterno di un blocco all’interno usando un’istruzione etichettata. In C ++, questo non è permesso se salta un’inizializzazione.

C è più liberale nel collegamento esterno. In C, una variabile const globale è implicitamente extern e ciò non è vero in C ++. C consente a un object dati globale di essere dichiarato diverse volte senza un extern , ma non è vero in C ++.

Molte parole chiave in C ++ non sono parole chiave in C o #define d in intestazioni C standard.

Ci sono anche alcune vecchie funzionalità di C che non sono più considerate di buon stile. In C, puoi dichiarare una funzione con le definizioni degli argomenti dopo l’elenco degli argomenti. In C, una dichiarazione come int foo() significa che foo() può prendere qualsiasi numero di qualsiasi tipo di argomento, mentre in C ++ è equivalente a int foo(void) .

Questo sembra coprire tutto da Stroustrup.

La più grande differenza credo sia che questo è un file sorgente C valido:

 int main() { foo(); } 

Nota che non ho dichiarato foo nessuna parte.

A parte le differenze linguistiche, C ++ apporta anche alcune modifiche alla libreria ereditata da C, ad esempio alcune funzioni restituiscono const char * invece di char * .

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

Vedi anche la voce FAQ C ++ .

Se si utilizza gcc, è ansible utilizzare l’avviso -Wc++-compat per fornire avvisi sul codice C che è dubbio in C ++ in qualche modo. Attualmente è in uso in gcc e di recente è migliorato molto (magari prova una versione notturna per ottenere il meglio che puoi).

(Questo non risponde in modo rigoroso alla domanda, ma la gente potrebbe piacere).

Un certo numero di risposte qui copre le differenze di syntax che farebbero fallire i compilatori C ++ sul codice sorgente C89 (o C99). Tuttavia, ci sono alcune sottili differenze linguistiche che sono legali in entrambe le lingue ma che produrrebbero un comportamento diverso. La differenza sizeof (char) menzionata da Naveen è un esempio, ma Scrivi un programma che stamperà “C” se compilato come programma (ANSI) C e “C ++” se compilato come programma C ++ ne elenca altri.

I compilatori C in genere hanno permesso di tagliare un angolo che il C ++ no. Il C ++ è molto più rigido di C. E in generale, alcune di queste differenze dipendono dal compilatore. g ++ consente alcune cose che il compilatore Intel C ++ non fa, per esempio. Anche il codice C ben scritto non verrà compilato con un compilatore C ++ moderno.

Non è ansible confrontare le lingue solo per syntax. Se lo fai forse puoi vedere C come un sottoinsieme di C ++. A mio parere il fatto che C ++ sia OO (e C non lo è) è sufficiente per dire che C e C ++ sono lingue diverse.