Dove C non è un sottoinsieme di C ++? [chiuso]


116

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 ++?

Risposte:


135

Se ti confronti C89con, C++ecco un paio di cose

Nessuna definizione provvisoria in C ++

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

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

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

Nessuno stile di definizione della funzione K&R

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

La struttura annidata ha un ambito di classe in C ++

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

Nessun int predefinito

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

C99 aggiunge un sacco di altri casi

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

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

Nessun array di lunghezza variabile

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

Nessun membro dell'array flessibile

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

Nessun qualificatore restrittivo per aiutare l'analisi dell'aliasing

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

@mehrdad, grazie. oO non sapeva che si doveva creare una variabile già quando si dichiarava una struttura annidata in C. Risolto.
Johannes Schaub - litb

3
C'è un altro (inutile) da C89 a C ++: typedef;è una TU legale in C, ma non in C ++.
Flexo

Si noti che auto a;è valido nella più recente revisione dello standard C ++.
fuz

3
@FUZxxl davvero? Quale sarà il tipo dedotto a?
Johannes Schaub - litb

3
@ FUZxxl ah grazie. Quindi auto x;non è valido nella revisione più recente, ma ad esempio lo auto x = 0;è.
All'inizio

50

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

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


46
Ciò può essere semplificato in: In C, 'a'è un file int. In C ++, 'a'è un file char.
pmg

38

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;

1
è vero, ma questo è esattamente ciò che significa subset.
yeyeyerman

20
@yeyeyerman: No. Perché sia ​​un sottoinsieme, tutto il codice C dovrebbe essere anche C ++ valido. Il codice in questo esempio è C valido ma non C ++.
jalf

24
No, se C fosse un sottoinsieme rigoroso di C ++, ogni programma C sarebbe un programma C ++ valido, ma non è vero. La domanda è perché non è vero, e questo è un esempio del perché.
Graeme Perrow,

Ha! Non ho pensato a questo!
Gab Royer

20

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

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

dovrebbe essere compilato in C ma non in C ++.


3
C ++ dovrebbe richiedere un cast esplicito a int*.
Mehrdad Afshari

8
Risposta lunga: malloc restituisce void *, che in C può essere assegnato a qualsiasi tipo di puntatore e C ++ non può essere assegnato a nessun altro tipo di puntatore.
Daniel Earwicker

5
Imagist: un compilatore C, come definito dallo standard ANSI C89, non dovrebbe lamentarsi.
Mehrdad Afshari

7
È legale C. Il cast non è necessario, è possibile sbagliare e copre un errore nell'inclusione di <stdlib.h>. Considero l'affermazione di Mehrdad il modo giusto per scriverla in C.
David Thornley,

16
@Imagist: di solito sento il contrario dai programmatori C. Considerano uno stile scadente aggiungere il cast, in quanto potrebbe nascondere bug. Un buon codice C non usa il cast.
jalf

16

In C ++, se si dichiara una struct, uniono enum, il suo nome è immediatamente accessibile senza qualificazioni:

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

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

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

Notare la presenza di structlì sulla seconda riga. Devi fare lo stesso per unione enum(usando le rispettive parole chiave) o usare il typedeftrucco:

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

Di conseguenza, puoi avere diversi tipi di tipi diversi con lo stesso nome in C, poiché puoi disambiguare:

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

struct foo x;
foo y;

In C ++, tuttavia, sebbene sia possibile anteporre a un structnome una parola chiave structogni volta che ci si fa riferimento, gli spazi dei nomi vengono uniti e quindi lo snippet C precedente non è valido. D'altra parte, C ++ fa specificamente un'eccezione per consentire a un tipo e un typedef per quel tipo di avere lo stesso nome (ovviamente senza alcun effetto), per consentire l'uso del typedeftrucco invariato da C.


1
Il tuo ultimo esempio è valido C: Le tre tag ( struct, unione enum) condividono lo stesso spazio dei nomi. Un esempio migliore potrebbe esserestruct foo { ... }; typedef enum { ... } foo;
schot

@schot: hai ovviamente ragione, grazie per la correzione. Aggiornato.
Pavel Minaev

8

Questo dipende anche dalla varietà di C che stai usando. Stroustrup ha reso C ++ il più compatibile possibile, e non più compatibile, con gli standard ANSI del 1989 e ISO del 1990, e la versione del 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 uscito il prossimo anno o giù di lì) per conformarsi ad alcune delle modifiche.

Stroustrup elenca le incompatibilità con C90 / C95 nell'Appendice B.2 di "The C ++ Programming Language", edizione speciale (che è la terza edizione con del materiale aggiunto):

'a'è una intin C, una charin C ++.

La dimensione di un'enumerazione è intin 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 viene fooinserita nello spazio dei nomi globale, mentre in C dovrebbe essere indicata come struct foo. Ciò consente a una structdefinizione di nascondere un nome in un ambito esterno e ha alcune altre conseguenze. Inoltre, C consente un ambito più ampio per le structdefinizioni e le consente nelle dichiarazioni di tipo restituito e tipo di argomento.

Il C ++ è più pignolo sui tipi in generale. Non consentirà l'assegnazione di un intero a un oggetto enume gli void *oggetti non possono essere assegnati ad altri tipi di puntatore senza un cast. In C, è possibile fornire un inizializzatore troppo grande (char name[5] = "David" dove C eliminerà il carattere null finale).

C89 consentiva implicito intin molti contesti e C ++ no. Ciò significa che tutte le funzioni devono essere dichiarate in C ++, mentre in C89 era spesso possibile cavarsela assumendo intper tutto ciò che era applicabile nella dichiarazione di funzione.

In C, è possibile saltare dall'esterno di un blocco all'interno utilizzando un'istruzione etichettata. In C ++, questo non è consentito se salta un'inizializzazione.

C è più liberale nei collegamenti esterni. In C, una constvariabile globale è implicitamente externe non è vero in C ++. C consente a un oggetto dati globale di essere dichiarato più volte senza un extern, ma non è vero in C ++.

Molte parole chiave C ++ non sono parole chiave in C o sono #defined nelle intestazioni C standard.

Ci sono anche alcune vecchie funzionalità di C che non sono più considerate un 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ò accettare qualsiasi numero di qualsiasi tipo di argomenti, mentre in C ++ è equivalente a int foo(void).

Questo sembra coprire tutto da Stroustrup.


Non dimentichiamo il fatto che, in C, devi dichiarare le variabili all'inizio di uno scope (cioè, immediatamente dopo una parentesi graffa aperta), mentre C ++ consente dichiarazioni di variabili ovunque.
RobH

4
Tuttavia, questo è qualcosa che C ++ può fare che C non può fare. Penso che stiamo esaminando le cose che puoi fare in C ma non in C ++.
David Thornley,

2
@ RobH: Questo è vero per C89 ma non per C99.
jamesdlin

6

Se usi gcc, puoi usare l'avviso -Wc++-compat per darti avvisi sul codice C che è in qualche modo dubbio in C ++. È attualmente utilizzato nello stesso gcc e recentemente è migliorato molto (magari prova una versione notturna per ottenere il meglio che puoi).

(Questo non risponde rigorosamente alla domanda, ma alla gente potrebbe piacere).


1
Ho pensato che non avrei mai
votato positivamente

4

L'unica più grande differenza che penso è che questo è un file sorgente C valido:

int main()
{
    foo();
}

Nota che non ho dichiarato foo nessuna parte.

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


Esatto, i prototipi non sono richiesti in C ma di solito è considerata una cattiva pratica non usarli.
Robert Gamble,

1
Dovresti farlo s,C,C89,e notare che si tratta di un file sorgente C99 non valido.
Johannes Schaub - litb

Tuttavia, non è valido o è solo deprecato in C99?
jalf

2
@jalf la bozza del C99 documenta le modifiche a C89 e include sia "remove implicit int" che "remove implicit function declaration".
Johannes Schaub - litb


2

Un certo numero di risposte qui copre differenze di sintassi che causerebbero il fallimento dei 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 comportamenti diversi. La sizeof (char)differenza menzionata da Naveen è un esempio, ma Scrivi un programma che stamperà "C" se compilato come un programma C (ANSI) e "C ++" se compilato come un programma C ++ ne elenca alcuni altri.


-2

I compilatori C generalmente consentivano un piccolo taglio degli angoli che C ++ non fa. Il C ++ è molto più rigoroso di C. E generalmente, alcune di queste differenze dipendono dal compilatore. g ++ consente alcune cose che il compilatore Intel C ++ non, ad esempio. Anche il codice C scritto abbastanza bene non verrà compilato con un moderno compilatore C ++.


-2

Non è possibile confrontare le lingue solo in base alla sintassi. Se lo fai, forse puoi vedere C come un sottoinsieme di C ++. Secondo me il fatto che C ++ sia OO (e C non lo è) è sufficiente per dire che C e C ++ sono linguaggi diversi.


2
Sbagliato. C ++ non è solo OO. Potresti pensare a C ++ qualcosa come "C ++ = C + OO + programmazione generica + bonus". Per dirla in un altro modo, "C e C ++ ~ = C" dove ~ = significa quasi uguale.
paercebal
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.