Gdzie C nie jest podzbiorem C ++? [Zamknięte]

116

Czytałem w wielu książkach, że C jest podzbiorem C ++.

Niektóre książki mówią, że C jest podzbiorem C ++, z wyjątkiem drobnych szczegółów .

Jakie są przypadki, gdy kod będzie kompilowany w C, ale nie w C ++?

n00ki3
źródło

Odpowiedzi:

135

Jeśli porównasz C89z, C++oto kilka rzeczy

Brak wstępnych definicji w C ++

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

int [] i int [N] nie są zgodne (brak zgodnych typów w C ++)

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

Brak stylu definicji funkcji K&R

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

Zagnieżdżona struktura ma zakres klasy w C ++

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

Brak domyślnego int

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

C99 dodaje całą masę innych przypadków

Brak specjalnej obsługi specyfikatorów deklaracji w wymiarach tablicy parametrów

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

Brak tablic o zmiennej długości

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

Brak elastycznego elementu tablicy

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

Kwalifikator bez ograniczeń ułatwiający analizę aliasingu

// ill-formed: two names for one parameter?
void copy(int *restrict src, int *restrict dst);
Johannes Schaub - litb
źródło
@mehrdad, dzięki. oO nie wiedziałem, że trzeba utworzyć zmienną już podczas deklarowania zagnieżdżonej struktury w C. Naprawiono.
Johannes Schaub - litb
3
Jest jeszcze jeden (bezużyteczny) C89 do C ++: typedef;to legalna jednostka TU w C, ale nie w C ++.
Flexo
Zwróć uwagę, że auto a;obowiązuje w najnowszej wersji standardu C ++.
fuz
3
@FUZxxl naprawdę? Jaki będzie wydedukowany typa ?
Johannes Schaub - litb
3
@FUZxxl ah thanks. Więc auto x;nie obowiązuje w najnowszej wersji, ale na przykład auto x = 0;jest. Na początku byłem trochę zszokowany :)
Johannes Schaub - litb
50

W C sizeof('a')jest równe sizeof(int).

W C ++ sizeof('a')jest równe sizeof(char).

Naveen
źródło
46
Można to uprościć do: W C 'a'jest int. W C ++ 'a'to plik char.
pmg
38

C ++ ma również nowe słowa kluczowe. Poniższy kod jest prawidłowym kodem w C, ale nie kompiluje się w C ++:

int class = 1;
int private = 2;
int public = 3;
int virtual = 4;
Graeme Perrow
źródło
1
to prawda, ale dokładnie to oznacza podzbiór.
yeyeyerman
20
@yeyeyerman: Nie. Aby był podzbiorem, cały kod C również musiałby być poprawny w C ++. Kod w tym przykładzie jest prawidłowy w C, ale nie w C ++.
jalf
24
Nie, gdyby C był ścisłym podzbiorem C ++, to każdy program w C byłby prawidłowym programem w C ++, ale to nieprawda. Pytanie brzmi, dlaczego to nieprawda, i to jest jeden z przykładów, dlaczego.
Graeme Perrow
Ha! Nie myślałem o tym!
Gab Royer
20

Jest mnóstwo rzeczy. Prosty przykład (wystarczy udowodnić, że C nie jest odpowiednim podzbiorem C ++):

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

powinien kompilować się w C, ale nie w C ++.

Mehrdad Afshari
źródło
3
C ++ powinien wymagać jawnego rzutowania do int*.
Mehrdad Afshari
8
Długa odpowiedź: zwraca malloc void *, które w C można przypisać do dowolnego typu wskaźnika, a C ++ nie może być przypisane do żadnego innego typu wskaźnika.
Daniel Earwicker
5
Imagist: kompilator C, zgodnie z definicją standardu ANSI C89, nie powinien narzekać.
Mehrdad Afshari
7
Jest to legalne C. Obsada jest niepotrzebna, można się pomylić i ukrywa niepowodzenie w dołączeniu <stdlib.h>. Uważam oświadczenie Mehrdad, aby być dobrym sposobem, aby zapisać go w C
David Thornley
16
@Imagist: Zwykle słyszę coś przeciwnego od programistów C. Uważają, że dodanie obsady jest kiepskim stylem, ponieważ może ukrywać błędy. Dobry kod C nie wykorzystuje rzutowania.
jalf
16

W C ++, jeśli zadeklarujesz a struct, unionlub enum, jego nazwa jest natychmiast dostępna bez żadnych kwalifikatorów:

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

W C to nie zadziała, ponieważ zadeklarowane w ten sposób typy żyją w swoich własnych odrębnych przestrzeniach nazw. Musisz więc napisać:

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

Zwróć uwagę na obecność structtam w drugiej linii. Musisz zrobić to samo dla unioni enum(używając odpowiednich słów kluczowych) lub użyć typedefsztuczki:

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

W związku z tym możesz mieć kilka typów różnych rodzajów nazwanych tak samo w C, ponieważ możesz ujednoznacznić:

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

struct foo x;
foo y;

Jednak w C ++, chociaż możesz poprzedzić structnazwę słowem kluczowym structza każdym razem, gdy się do niej odwołujesz, przestrzenie nazw są scalane, więc powyższy fragment C jest nieprawidłowy. Z drugiej strony, C ++ robi wyjątek, aby pozwolić typowi i definicji typu dla tego typu mieć tę samą nazwę (oczywiście bez efektu), aby umożliwić użycie typedeftriku niezmienionego od C.

Pavel Minaev
źródło
1
Twój ostatni przykład jest nieprawidłowy C: Trzy Tagi ( struct, unioni enum) udział ten sam nazw. Lepszym przykładem może byćstruct foo { ... }; typedef enum { ... } foo;
schot
@schot: masz oczywiście rację, dziękuję za korektę. Zaktualizowano.
Pavel Minaev
8

Zależy to również od używanej odmiany C. Stroustrup uczynił C ++ tak kompatybilnym, jak tylko mógł, a nie bardziej kompatybilnym, z normami ISO 1989 ANSI i 1990, a wersja 1995 niczego nie zmieniła. Komisja C poszła w nieco innym kierunku ze standardem 1999, a komisja C ++ zmieniła następny standard C ++ (prawdopodobnie w przyszłym roku), aby dostosować się do niektórych zmian.

Stroustrup wymienia niezgodności z C90 / C95 w Dodatku B.2 „Języka programowania C ++”, wydanie specjalne (czyli wydanie trzecie z dodatkowymi materiałami):

'a'jest intw C, achar w C ++.

Rozmiar wyliczenia to int w C, niekoniecznie w C ++.

C ++ ma // komentarze na końcu linii, C nie (chociaż jest to powszechne rozszerzenie).

W C ++ struct foo {definicja umieszczana jest foow globalnej przestrzeni nazw, podczas gdy w C musiałaby być nazywana struct foo. Pozwala to structdefinicji przesłonić nazwę w zakresie zewnętrznym i ma kilka innych konsekwencji. Ponadto C umożliwia większy zakresstruct definicji i zezwala na ich deklaracje typu zwracanego i typu argumentu.

C ++ jest ogólnie bardziej zawstydzony co do typów. Nie pozwoli na przypisanie liczby całkowitej do obiektu enum, a void *obiekty nie mogą być przypisane do innych typów wskaźników bez rzutowania. W C można podać zbyt duży inicjator (char name[5] = "David" gdzie C odrzuci końcowy znak null).

C89 jest dozwolone intw wielu kontekstach, a C ++ nie. Oznacza to, że wszystkie funkcje muszą być zadeklarowane w C ++, podczas gdy w C89 często można było załatwić intwszystko, co ma zastosowanie w deklaracji funkcji.

W C można przeskoczyć z zewnątrz bloku do wewnątrz za pomocą instrukcji z etykietą. W C ++ nie jest to dozwolone, jeśli pomija inicjalizację.

C jest bardziej liberalny w połączeniach zewnętrznych. W C constzmienna globalna jest niejawnie extern, aw C ++ to nieprawda. C pozwala na kilkakrotne zadeklarowanie globalnego obiektu danych bez znaku extern, ale nie jest to prawdą w C ++.

Wiele słów kluczowych w języku C ++ nie jest słowami kluczowymi w języku C lub występuje #definew standardowych nagłówkach C.

Istnieją również starsze funkcje C, które nie są już uważane za dobry styl. W C możesz zadeklarować funkcję z definicjami argumentów po liście argumentów. W C deklaracja taka jak int foo()oznacza, która foo()może przyjąć dowolną liczbę argumentów dowolnego typu, podczas gdy w C ++ jest to odpowiednik int foo(void).

Wydaje się, że obejmuje wszystko od Stroustrup.

David Thornley
źródło
Nie zapominajmy, że w C musisz zadeklarować zmienne na początku zakresu (tj. Bezpośrednio po nawiasie otwierającym), podczas gdy C ++ pozwala na deklaracje zmiennych w dowolnym miejscu.
RobH
4
Jest to jednak coś, co C ++ może zrobić, czego C nie może. Myślę, że patrzymy na rzeczy, które można zrobić w C, ale nie w C ++.
David Thornley
2
@RobH: To prawda dla C89, ale nie dla C99.
jamesdlin
6

Jeśli używasz gcc, możesz użyć ostrzeżenia -Wc++-compat do ostrzeżenia o kodzie w C, który jest w jakiś sposób wątpliwy w C ++. Obecnie jest używany w samym gcc, a ostatnio stał się znacznie lepszy (może spróbuj nocnej wersji, aby uzyskać najlepsze możliwe).

(To nie jest dokładną odpowiedzią na pytanie, ale ludziom może się to podobać).

Paul Biggar
źródło
1
Myślałem, że nigdy nie zagłosuję za brakiem odpowiedzi
eharo2,
4

Myślę, że największą różnicą jest to, że jest to prawidłowy plik źródłowy w języku C:

int main()
{
    foo();
}

Zauważ, że nie zadeklarowałem foo nigdzie .

Oprócz różnic językowych, C ++ wprowadza również pewne zmiany w bibliotece, którą odziedziczył po C, np. Niektóre funkcje zwracają const char *zamiast char *.

Daniel Earwicker
źródło
Owszem, prototypy nie są wymagane w C, ale niestosowanie ich jest zwykle uważane za złą praktykę.
Robert Gamble
1
Powinieneś to zrobić s,C,C89,i zauważyć, że jest to nieprawidłowy plik źródłowy C99.
Johannes Schaub - litb
Czy jest to nieprawidłowe, czy po prostu przestarzałe w C99?
jalf
2
@jalf wersja robocza C99 dokumentuje zmiany w C89 i zawiera zarówno „remove implicit int”, jak i „remove niejawną deklarację funkcji”.
Johannes Schaub - litb
4
#include <stdio.h>

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

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

Zobacz także wpis C ++ FAQ .

Sinan Ünür
źródło
2

Szereg odpowiedzi tutaj dotyczy różnic w składni, które mogą spowodować niepowodzenie kompilatorów C ++ w kodzie źródłowym C89 (lub C99). Istnieją jednak pewne subtelne różnice językowe, które są legalne w obu językach, ale skutkują różnymi zachowaniami. sizeof (char)Różnicą, że Naveen wspomniano jest jednym z przykładów, ale Napisz program, który będzie drukować „C”, jeśli skompilowany jako (ANSI) C programu, a „C ++” czy kompilowany jako C ++ programu list inni.

jamesdlin
źródło
-2

Kompilatory C generalnie pozwalały na małe cięcie narożników, czego C ++ nie robi. C ++ jest dużo bardziej rygorystyczny niż C. I ogólnie, niektóre z tych różnic są zależne od kompilatora. g ++ pozwala na pewne rzeczy, na przykład kompilator Intel C ++. Nawet całkiem dobrze napisany kod w C nie da się skompilować za pomocą nowoczesnego kompilatora C ++.

xcramps
źródło
-2

Nie można porównywać języków tylko za pomocą składni. Jeśli to zrobisz, być może zobaczysz C jako podzbiór C ++. Moim zdaniem fakt, że C ++ to OO (a C nie jest) wystarczy, aby powiedzieć, że C i C ++ to różne języki.

fnurglewitz
źródło
2
Źle. C ++ to nie tylko OO. Można by pomyśleć w C ++ coś w stylu „C ++ = C + OO + programowanie ogólne + bonusy”. Innymi słowy, „C i C ++ ~ = C”, gdzie ~ = oznacza prawie równe.
paercebal