Où C n'est-il pas un sous-ensemble de C ++? [fermé]

116

J'ai lu dans beaucoup de livres que C est un sous-ensemble de C ++.

Certains livres disent que C est un sous-ensemble de C ++, à l' exception des petits détails .

Dans quels cas le code se compilera-t-il en C, mais pas en C ++?

n00ki3
la source

Réponses:

135

Si vous comparez C89avec, C++voici quelques choses

Aucune définition provisoire en C ++

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

int [] et int [N] non compatibles (pas de types compatibles en C ++)

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

Pas de style de définition de fonction K&R

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

La structure imbriquée a une portée de classe en C ++

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

Aucun int par défaut

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

C99 ajoute de nombreux autres boîtiers

Pas de traitement spécial des spécificateurs de déclaration dans les dimensions de tableau des paramètres

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

Pas de tableaux de longueur variable

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

Pas de membre flexible du tableau

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

Aucun qualificatif de restriction pour aider l'analyse d'aliasing

// ill-formed: two names for one parameter?
void copy(int *restrict src, int *restrict dst);
Johannes Schaub - litb
la source
@mehrdad, merci. oO ne savait pas qu'il fallait déjà créer une variable lors de la déclaration d'une structure imbriquée en C. Corrigé.
Johannes Schaub - litb le
3
Il y a un autre (inutile) C89 à C ++: typedef;est un TU légal en C, mais pas en C ++.
Flexo
Notez que cela auto a;est valide dans la dernière révision standard C ++.
fuz le
3
@FUZxxl vraiment? Quel sera le type déduit de a?
Johannes Schaub - litb
3
@FUZxxl ah merci. Donc auto x;n'est pas valide dans la dernière révision, mais par exemple auto x = 0;. J'ai été un peu choqué au début :)
Johannes Schaub - litb
50

En C, sizeof('a')est égal à sizeof(int).

En C ++, sizeof('a') est égal à sizeof(char).

Naveen
la source
46
Cela peut être simplifié en: En C, 'a'est un int. En C ++, 'a'est un char.
pmg
38

C ++ a également de nouveaux mots clés. Ce qui suit est du code C valide mais ne sera pas compilé sous C ++:

int class = 1;
int private = 2;
int public = 3;
int virtual = 4;
Graeme Perrow
la source
1
c'est vrai, mais c'est exactement ce que signifie le sous-ensemble.
yeyeyerman le
20
@yeyeyerman: Non. Pour que ce soit un sous-ensemble, tout le code C devrait également être C ++ valide. Le code de cet exemple est C valide mais pas C ++.
jalf
24
Non, si C était un sous-ensemble strict de C ++, alors chaque programme C serait un programme C ++ valide, mais ce n'est pas vrai. La question est de savoir pourquoi ce n'est pas vrai, et c'est un exemple de pourquoi.
Graeme Perrow
Ha! Je n'ai pas pensé à celui-ci!
Gab Royer
20

Il y a plein de choses. Juste un exemple simple (cela devrait suffire à prouver que C n'est pas un sous-ensemble approprié de C ++):

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

devrait compiler en C mais pas en C ++.

Mehrdad Afshari
la source
3
C ++ doit nécessiter un cast explicite en int*.
Mehrdad Afshari
8
Réponse longue: malloc renvoie void *, qui en C peut être assigné à n'importe quel type de pointeur, et C ++ ne peut être assigné à aucun autre type de pointeur.
Daniel Earwicker
5
Imagist: un compilateur C, tel que défini par la norme ANSI C89, ne devrait pas se plaindre.
Mehrdad Afshari
7
C'est légal C. Le cast est inutile, il est possible de se tromper et couvre l'échec de l'inclusion de <stdlib.h>. Je considère que la déclaration de Mehrdad est la bonne façon de l'écrire en C.
David Thornley
16
@Imagist: J'entends généralement le contraire des programmeurs C. Ils considèrent qu'il est peu judicieux d'ajouter le casting, car cela peut cacher des bugs. Le bon code C n'utilise pas le cast.
jalf le
16

En C ++, si vous déclarez un struct , unionou enum, son nom est immédiatement accessible sans qualification:

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

En C, cela ne fonctionnera pas, car les types ainsi déclarés vivent dans leurs propres espaces de noms distincts. Ainsi, vous devez écrire:

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

Remarquez la présence de structlà sur la deuxième ligne. Vous devez faire de même pourunion et enum(en utilisant leurs mots-clés respectifs), ou utiliser l' typedefastuce:

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

Par conséquent, vous pouvez avoir plusieurs types de types différents nommés de la même manière en C, car vous pouvez lever l'ambiguïté:

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

struct foo x;
foo y;

En C ++, cependant, alors que vous pouvez préfixer un structnom avec un mot-clé structchaque fois que vous le référencez, les espaces de noms sont fusionnés, et donc l'extrait de code C ci-dessus n'est pas valide. D'autre part, C ++ fait spécifiquement une exception pour permettre à un type et à un typedef pour ce type d'avoir le même nom (évidemment sans effet), pour permettre l'utilisation de typedeftruc inchangé depuis C.

Pavel Minaev
la source
1
Votre dernier exemple n'est pas valide C: les trois balises ( struct, unionet enum) partagent le même espace de noms. Un meilleur exemple seraitstruct foo { ... }; typedef enum { ... } foo;
schot
@schot: vous avez bien sûr raison, merci pour la correction. Actualisé.
Pavel Minaev
8

Cela dépend également de la variété de C que vous utilisez. Stroustrup a rendu C ++ aussi compatible qu'il le pouvait, et non plus compatible, avec les normes ANSI de 1989 et ISO de 1990, et la version de 1995 n'a rien changé. Le comité C est allé dans une direction quelque peu différente avec la norme de 1999, et le comité C ++ a changé la prochaine norme C ++ (probablement sortie l'année prochaine environ) pour se conformer à certains des changements.

Stroustrup répertorie les incompatibilités avec C90 / C95 dans l'annexe B.2 de "The C ++ Programming Language", Special Edition (qui est la 3e édition avec du matériel supplémentaire):

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

La taille d'une énumération est inten C, pas nécessairement en C ++.

C ++ a des //commentaires à la fin de la ligne, pas C (bien que ce soit une extension courante).

En C ++, une struct foo {définition place foodans l'espace de noms global, tandis qu'en C, il faudrait l'appeler struct foo. Cela permet à une structdéfinition d'observer un nom dans une portée externe et a quelques autres conséquences. De plus, C permet une plus grande portée pour les structdéfinitions et les autorise dans les déclarations de type de retour et de type d'argument.

C ++ est plus difficile à propos des types en général. Il ne permet pas d'affecter un entier à un enum, et les void *objets ne peuvent pas être affectés à d'autres types de pointeurs sans conversion. En C, il est possible de fournir un initialiseur surdimensionné (char name[5] = "David" où C le caractère nul de fin).

C89 autorisé implicitement intdans de nombreux contextes, et C ++ ne le fait pas. Cela signifie que toutes les fonctions doivent être déclarées en C ++, alors qu'en C89, il était souvent possible de se débrouiller en supposant inttout ce qui est applicable dans la déclaration de fonction.

En C, il est possible de sauter de l'extérieur d'un bloc vers l'intérieur en utilisant une instruction étiquetée. En C ++, cela n'est pas autorisé s'il ignore une initialisation.

C est plus libéral en matière de liens externes. En C, une constvariable globale est implicitement extern, et ce n'est pas vrai en C ++. C permet à un objet de données global d'être déclaré plusieurs fois sansextern , mais ce n'est pas le cas en C ++.

De nombreux mots-clés C ++ ne sont pas des mots-clés en C ou sont #defined dans les en-têtes C standard.

Il existe également des fonctionnalités plus anciennes de C qui ne sont plus considérées comme du bon style. En C, vous pouvez déclarer une fonction avec les définitions d'arguments après la liste d'arguments. En C, une déclaration comme int foo()signifie que foo()peut prendre n'importe quel nombre d'arguments de n'importe quel type, alors qu'en C ++, c'est équivalent à int foo(void).

Cela semble couvrir tout de Stroustrup.

David Thornley
la source
N'oublions pas que, en C, vous devez déclarer des variables au début d'une portée (c'est-à-dire immédiatement après une accolade ouvrante), alors que C ++ autorise les déclarations de variables n'importe où.
RobH
4
Cependant, c'est quelque chose que C ++ peut faire que C ne peut pas faire. Je pense que nous examinons des choses que vous pouvez faire en C mais pas en C ++.
David Thornley le
2
@RobH: C'est vrai pour C89 mais pas pour C99.
jamesdlin
6

Si vous utilisez gcc, vous pouvez utiliser l'avertissement -Wc++-compat pour vous donner des avertissements sur le code C qui est douteux en C ++ d'une certaine manière. Il est actuellement utilisé dans gcc lui-même, et il s'est beaucoup amélioré récemment (essayez peut-être une version nocturne pour obtenir le meilleur possible).

(Cela ne répond pas strictement à la question, mais les gens pourraient l'aimer).

Paul Biggar
la source
1
Je pensais que je ne voterais jamais pour une réponse sans réponse
eharo2
4

La plus grande différence que je pense est qu'il s'agit d'un fichier source C valide:

int main()
{
    foo();
}

Notez que je n'ai déclaré foonulle part.

Mis à part les différences de langage, C ++ apporte également des modifications à la bibliothèque dont il a hérité de C, par exemple certaines fonctions retournent à la const char *place de char *.

Daniel Earwicker
la source
Bon, les prototypes ne sont pas nécessaires en C mais il est généralement considéré comme une mauvaise pratique de ne pas les utiliser.
Robert Gamble
1
Vous devez faire s,C,C89,et noter qu'il s'agit d'un fichier source C99 non valide.
Johannes Schaub - litb le
Est-il invalide ou simplement obsolète dans C99?
jalf
2
@jalf le brouillon C99 documente les modifications apportées à C89, et inclut à la fois "remove implicit int" et "remove implicit function declaration".
Johannes Schaub - litb le
4
#include <stdio.h>

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

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

Voir également l'entrée FAQ C ++ .

Sinan Ünür
la source
2

Un certain nombre de réponses ici couvrent les différences de syntaxe qui entraîneraient l'échec des compilateurs C ++ sur le code source C89 (ou C99). Cependant, il existe des différences linguistiques subtiles qui sont légales dans les deux langues, mais qui entraîneraient un comportement différent. La sizeof (char)différence mentionnée par Naveen est un exemple, mais Ecrire un programme qui affichera «C» s'il est compilé en tant que programme C (ANSI) et «C ++» s'il est compilé en tant que programme C ++ en énumère d'autres.

Jamesdlin
la source
-2

Les compilateurs C permettaient généralement une petite coupe de coin, contrairement à C ++. C ++ est beaucoup plus strict que C. Et généralement, certaines de ces différences dépendent du compilateur. g ++ autorise certaines choses que le compilateur Intel C ++ ne permet pas, par exemple. Même un code C assez bien écrit ne sera pas compilé avec un compilateur C ++ moderne.

xcramps
la source
-2

Vous ne pouvez pas comparer les langues uniquement par syntaxe. Si vous faites cela, vous pouvez peut-être voir C comme un sous-ensemble de C ++. À mon avis, le fait que C ++ soit OO (et C ne l'est pas) suffit à dire que C et C ++ sont des langages différents.

Fnurglewitz
la source
2
Faux. C ++ n'est pas seulement OO. Vous pourriez penser à C ++ quelque chose comme "C ++ = C + OO + programmation générique + bonus". Pour le dire autrement, "C & C ++ ~ = C" où ~ = signifie presque égal.
paercebal