Wo ist C keine Teilmenge von C ++? [geschlossen]

116

Ich habe in vielen Büchern gelesen, dass C eine Teilmenge von C ++ ist.

Einige Bücher sagen, dass C eine Teilmenge von C ++ ist, abgesehen von den kleinen Details .

In welchen Fällen wird Code in C kompiliert, nicht jedoch in C ++?

n00ki3
quelle

Antworten:

135

Wenn Sie vergleichen C89mit C++dann sind hier ein paar Dinge ,

Keine vorläufigen Definitionen in C ++

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

int [] und int [N] nicht kompatibel (keine kompatiblen Typen in C ++)

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

Kein K & R-Funktionsdefinitionsstil

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

Verschachtelte Struktur hat Klassenbereich in C ++

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

Kein Standard-Int

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

C99 fügt eine ganze Reihe anderer Fälle hinzu

Keine spezielle Behandlung von Deklarationsspezifizierern in Array-Dimensionen von Parametern

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

Keine Arrays variabler Länge

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

Kein flexibles Array-Mitglied

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

Keine Einschränkung für die Unterstützung der Aliasing-Analyse

// ill-formed: two names for one parameter?
void copy(int *restrict src, int *restrict dst);
Johannes Schaub - litb
quelle
@mehrdad, danke. oO wusste nicht, dass man bereits eine Variable erstellen muss, wenn man eine verschachtelte Struktur in C deklariert. Behoben.
Johannes Schaub - litb
3
Es gibt eine andere (nutzlose) C89 zu C ++: typedef;ist eine legale TU in C, aber nicht in C ++.
Flexo
Beachten Sie, dass dies auto a;in der neuesten C ++ - Standardversion gültig ist.
Fuz
3
@FUZxxl wirklich? Was wird der abgeleitete Typ sein a?
Johannes Schaub - litb
3
@FUZxxl ah danke. Ist auto x;also in der neuesten Version nicht gültig, ist es aber zum Beispiel auto x = 0;. Ich war zuerst ein bisschen schockiert :)
Johannes Schaub - litb
50

In C sizeof('a')ist gleich sizeof(int).

In C ++ sizeof('a')ist gleich sizeof(char).

Naveen
quelle
46
Das kann vereinfacht werden zu: In C 'a'ist ein int. In C ++ 'a'ist a char.
PMG
38

C ++ hat auch neue Schlüsselwörter. Folgendes ist gültiger C-Code, wird jedoch unter C ++ nicht kompiliert:

int class = 1;
int private = 2;
int public = 3;
int virtual = 4;
Graeme Perrow
quelle
1
es ist wahr, aber genau das bedeutet Teilmenge.
Yeyeyerman
20
@yeyeyerman: Nein. Damit es sich um eine Teilmenge handelt, muss der gesamte C-Code auch in C ++ gültig sein. Der Code in diesem Beispiel ist gültiges C, aber nicht C ++.
Jalf
24
Nein, wenn C eine strikte Teilmenge von C ++ wäre, wäre jedes C-Programm ein gültiges C ++ - Programm, aber das stimmt nicht. Die Frage ist, warum es nicht wahr ist, und dies ist ein Beispiel dafür, warum.
Graeme Perrow
Ha! Ich habe nicht an diesen gedacht!
Gab Royer
20

Es gibt viele Dinge. Nur ein einfaches Beispiel (es sollte ausreichen zu beweisen, dass C keine richtige Teilmenge von C ++ ist):

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

sollte in C kompiliert werden, aber nicht in C ++.

Mehrdad Afshari
quelle
3
C ++ sollte eine explizite Umwandlung in erfordern int*.
Mehrdad Afshari
8
Lange Antwort: malloc gibt zurück void *, das in C einem beliebigen Zeigertyp zugewiesen werden kann, und C ++ kann keinem anderen Zeigertyp zugewiesen werden.
Daniel Earwicker
5
Imagist: Ein C-Compiler im Sinne des ANSI C89-Standards sollte sich nicht beschweren.
Mehrdad Afshari
7
Es ist legal C. Die Besetzung ist unnötig, kann falsch sein und vertuscht einen Fehler beim Einfügen von <stdlib.h>. Ich halte Mehrdads Aussage für den richtigen Weg, sie in C zu schreiben.
David Thornley
16
@ Imagist: Normalerweise höre ich das Gegenteil von C-Programmierern. Sie halten es für einen schlechten Stil, die Besetzung hinzuzufügen, da dies Fehler verbergen kann. Gut C - Code ist nicht verwenden , um die Besetzung.
Jalf
16

Wenn Sie in C ++ ein struct, unionoder deklarieren , enumist der Name sofort ohne Qualifizierer zugänglich:

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

In C funktioniert dies nicht, da die so deklarierten Typen in ihren eigenen Namespaces leben. Sie müssen also schreiben:

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

Beachten Sie das Vorhandensein von structdort in der zweiten Zeile. Sie müssen dasselbe für unionund enum(unter Verwendung der entsprechenden Schlüsselwörter) tun oder den typedefTrick verwenden:

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

Folglich können Sie in C mehrere Arten verschiedener Arten haben, die gleich benannt sind, da Sie Folgendes unterscheiden können:

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

struct foo x;
foo y;

In C ++ können Sie einem structNamen zwar bei structjedem Verweis ein Schlüsselwort voranstellen , die Namespaces werden jedoch zusammengeführt, sodass das obige C-Snippet nicht gültig ist. Andererseits macht C ++ speziell eine Ausnahme, um zuzulassen, dass ein Typ und ein Typedef für diesen Typ denselben Namen haben (offensichtlich ohne Auswirkung), um die Verwendung eines typedefTricks zu ermöglichen, der von C unverändert bleibt .

Pavel Minaev
quelle
1
Ihr letztes Beispiel ist ungültig C: Die drei Tags ( struct, unionund enum) den gleichen Namensraum teilen. Ein besseres Beispiel wärestruct foo { ... }; typedef enum { ... } foo;
Schot
@schot: du hast natürlich recht, danke für die korrigierung. Aktualisiert.
Pavel Minaev
8

Dies hängt auch davon ab, welche C-Variante Sie verwenden. Stroustrup machte C ++ so kompatibel wie möglich und nicht mehr kompatibel mit den ANSI- und ISO-Standards von 1989 und 1990, und die Version von 1995 änderte nichts. Das C-Komitee ging mit dem Standard von 1999 in eine etwas andere Richtung, und das C ++ - Komitee hat den nächsten C ++ - Standard (wahrscheinlich nächstes Jahr oder so) geändert, um einigen Änderungen zu entsprechen.

Stroustrup listet Inkompatibilitäten mit C90 / C95 in Anhang B.2 von "The C ++ Programming Language", Special Edition (3. Auflage mit zusätzlichem Material) auf:

'a'ist ein intin C, ein charin C ++.

Die Größe einer Aufzählung ist intin C angegeben, nicht unbedingt in C ++.

C ++ hat //Kommentare am Zeilenende, C nicht (obwohl es eine übliche Erweiterung ist).

In C ++ wird eine struct foo {Definition fooin den globalen Namespace eingefügt, während sie in C als bezeichnet werden müsste struct foo. Dies ermöglicht einer structDefinition, einen Namen in einem äußeren Bereich zu schattieren, und hat einige andere Konsequenzen. Außerdem erlaubt C einen größeren Spielraum für structDefinitionen und erlaubt sie in Rückgabetyp- und Argumenttypdeklarationen.

C ++ ist in Bezug auf Typen im Allgemeinen umständlicher. Es ist nicht möglich, einer Ganzzahl eine Ganzzahl zuzuweisen enum, und void *Objekte können ohne Umwandlung keinen anderen Zeigertypen zugewiesen werden. In C ist es möglich, einen übergroßen Initialisierer bereitzustellen ( char name[5] = "David"wobei C das nachfolgende Nullzeichen verwirft).

C89 ist intin vielen Kontexten implizit erlaubt und C ++ nicht. Dies bedeutet, dass alle Funktionen in C ++ deklariert werden müssen, während es in C89 oft möglich war, intfür alles, was in der Funktionsdeklaration anwendbar ist , auszukommen .

In C ist es möglich, mit einer beschrifteten Anweisung von außerhalb eines Blocks nach innen zu springen. In C ++ ist dies nicht zulässig, wenn eine Initialisierung übersprungen wird.

C ist liberaler in der externen Verknüpfung. In C ist eine globale constVariable implizit externund in C ++ nicht wahr. Mit C kann ein globales Datenobjekt mehrmals ohne ein deklariert werden extern, dies ist jedoch in C ++ nicht der Fall.

Viele C ++ - Schlüsselwörter sind keine Schlüsselwörter in C oder #defined in Standard-C-Headern.

Es gibt auch einige ältere Funktionen von C, die nicht mehr als guter Stil angesehen werden. In C können Sie eine Funktion mit den Argumentdefinitionen nach der Liste der Argumente deklarieren. In C int foo()bedeutet eine Deklaration wie , dass foo()eine beliebige Anzahl von Argumenten jeder Art akzeptiert werden kann, während sie in C ++ äquivalent zu ist int foo(void).

Das scheint alles von Stroustrup abzudecken.

David Thornley
quelle
Vergessen wir nicht, dass Sie in C Variablen am Anfang eines Bereichs deklarieren müssen (dh unmittelbar nach einer öffnenden Klammer), während C ++ überall Variablendeklarationen zulässt.
RobH
4
Dies kann C ++ jedoch, was C nicht kann. Ich denke, wir schauen uns Dinge an, die Sie in C tun können, aber nicht in C ++.
David Thornley
2
@RobH: Das gilt für C89, aber nicht für C99.
Jamesdlin
6

Wenn Sie gcc verwenden, können Sie die Warnung verwenden -Wc++-compat, um Sie vor C-Code zu warnen , der in C ++ in irgendeiner Weise zweifelhaft ist. Es wird derzeit in gcc selbst verwendet und ist in letzter Zeit viel besser geworden (versuchen Sie es vielleicht mit einer nächtlichen Version, um das Beste zu bekommen, was Sie können).

(Dies beantwortet die Frage nicht unbedingt, aber die Leute mögen es vielleicht).

Paul Biggar
quelle
1
Ich dachte, ich würde niemals eine Antwort ohne Antwort
positiv bewerten
4

Der größte Unterschied besteht meiner Meinung nach darin, dass dies eine gültige C-Quelldatei ist:

int main()
{
    foo();
}

Beachten Sie, dass ich foonirgendwo deklariert habe .

Abgesehen von Sprachunterschieden nimmt C ++ auch einige Änderungen an der Bibliothek vor, die es von C geerbt hat, z. B. geben einige Funktionen const char *statt zurück char *.

Daniel Earwicker
quelle
Richtig, Prototypen sind in C nicht erforderlich, aber es wird normalerweise als schlechte Praxis angesehen, sie nicht zu verwenden.
Robert Gamble
1
Sie sollten s,C,C89,beachten, dass es sich um eine ungültige C99-Quelldatei handelt.
Johannes Schaub - litb
Ist es in C99 ungültig oder nur veraltet?
Jalf
2
@jalf Der C99-Entwurf dokumentiert die Änderungen an C89 und enthält sowohl "implizites int entfernen" als auch "implizite Funktionsdeklaration entfernen".
Johannes Schaub - litb
4
#include <stdio.h>

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

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

Siehe auch den C ++ - FAQ-Eintrag .

Sinan Ünür
quelle
2

Einige der Antworten hier beziehen sich auf Syntaxunterschiede, die dazu führen würden, dass C ++ - Compiler im C89- (oder C99-) Quellcode fehlschlagen. Es gibt jedoch einige subtile Sprachunterschiede, die in beiden Sprachen legal sind, aber zu unterschiedlichem Verhalten führen würden. Der sizeof (char)Unterschied, den Naveen erwähnte, ist ein Beispiel, aber Schreiben Sie ein Programm, das "C" druckt, wenn es als (ANSI) C-Programm kompiliert wird, und "C ++", wenn es als C ++ - Programm kompiliert wird, listet einige andere auf.

Jamesdlin
quelle
-2

C-Compiler erlaubten im Allgemeinen ein kleines Schneiden von Ecken, das C ++ nicht zulässt. C ++ ist viel strenger als C. Und im Allgemeinen sind einige dieser Unterschiede vom Compiler abhängig. g ++ erlaubt einige Dinge, die der Intel C ++ - Compiler zum Beispiel nicht tut. Selbst ziemlich gut geschriebener C-Code lässt sich mit einem modernen C ++ - Compiler nicht kompilieren.

xcramps
quelle
-2

Sie können Sprachen nicht nur nach Syntax vergleichen. Wenn Sie das tun, können Sie C vielleicht als Teilmenge von C ++ sehen. Meiner Meinung nach reicht die Tatsache, dass C ++ OO ist (und C nicht), aus, um zu sagen, dass C und C ++ verschiedene Sprachen sind.

fnurglewitz
quelle
2
Falsch. C ++ ist nicht nur OO. Sie könnten C ++ so etwas wie "C ++ = C + OO + generische Programmierung + Boni" denken. Anders ausgedrückt bedeutet "C & C ++ ~ = C", wobei ~ = fast gleich bedeutet.
Paercebal