Де C не є підмножиною C ++? [зачинено]


116

Я читав у багатьох книгах, що C - це підмножина C ++.

У деяких книгах сказано, що C - це підмножина C ++, за винятком дрібних деталей .

Які випадки, коли код буде компілюватися в C, але не C ++?

Відповіді:


135

Якщо порівнювати C89з, C++то ось кілька речей

Немає попередніх визначень у C ++

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

int [] та int [N] не сумісні (немає сумісних типів у C ++)

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

Немає стилю визначення функції K&R

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

Вкладена структура має область класу в C ++

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

Немає int за замовчуванням

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

C99 додає ще безліч інших випадків

Немає спеціальної обробки специфікаторів декларації в розмірах параметрів масиву

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

Немає масивів змінної довжини

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

Немає гнучкого члена масиву

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

Немає обмежених кваліфікуючих засобів, які допомагають провести аналіз

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

@mehrdad, спасибі oO не знав, що треба створювати змінну вже при оголошенні вкладеної структури в C. Fixed.
Йоханнес Шауб - ліб

3
Є ще один (марний) C89 - C ++ один: typedef;це юридичний TU в C, але не в C ++.
Flexo

Зауважте, що auto a;це дійсно в останній версії стандарту C ++.
фуз

3
@FUZxxl справді? Яким буде виведений тип a?
Йоханнес Шауб - ліб

3
@FUZxxl ах спасибі Отже auto x;, невірно в останній редакції, але, наприклад, auto x = 0;є. Спочатку я був трохи шокований :)
Йоганнес Шауб - ліб

50

В C sizeof('a')дорівнює sizeof(int).

У C ++ sizeof('a')дорівнює sizeof(char).


46
Це може бути спрощено до: У C 'a'- це int. В C ++, 'a'є a char.
pmg

38

C ++ також має нові ключові слова. Нижче наведено дійсний код C, але він не компілюється під C ++:

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

1
це правда, але саме це означає підмножина.
yeyeyerman

20
@yeyeyerman: Ні. Щоб це було підмножиною, весь код C повинен був бути дійсним також і C ++. Код у цьому прикладі є дійсним C, але не C ++.
jalf

24
Ні, якщо C був суворим підмножиною C ++, то кожна програма C була б дійсною програмою C ++, але це неправда. Питання в тому, чому це неправда, і це один із прикладів того, чому.
Graeme Perrow

Га! Не думав про це!
Габ Ройер

20

Речей багато. Просто простий приклад (цього має бути достатньо, щоб довести, що C не є належним підмножиною C ++):

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

слід компілювати в C, але не в C ++.


3
C ++ повинен вимагати явного перетворення на int*.
Мехрдад Афшарі

8
Відповідь довга: повертається malloc void *, який в C може бути призначений будь-якому типу вказівника, а C ++ не може бути призначений жодному іншому типу вказівника.
Даніель Ервікер

5
Imagist: компілятор C, визначений стандартом ANSI C89, не повинен скаржитися.
Мехрдад Афшарі

7
Це законно. Заголовок непотрібний, можливо, помиляється і приховує невключення <stdlib.h>. Я вважаю, що заява Мехрдада є правильним способом написати це в C.
Девід Торнлі

16
@Imagist: Я зазвичай чую протилежне від програмістів С. Вони вважають поганим стилем додавання ролі, оскільки це може приховати помилки. Хороший код C не використовує анонси.
jalf

16

У C ++, якщо ви оголосили a struct, unionабо enum, його ім'я буде негайно доступно без будь-яких кваліфікуючих осіб:

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

У C це не спрацює, оскільки типи, проголошені таким чином, живуть у власних просторах імен. Таким чином, ви повинні написати:

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

Зауважте наявність structтам у другому рядку. Ви повинні зробити те ж саме для unionі enum(використовуючи відповідні ключові слова) або скористатися typedefтрюком:

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

Отже, у вас може бути кілька типів різних типів, названих однаковими в C, оскільки ви можете роз'єднати:

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

struct foo x;
foo y;

Однак у C ++, хоча ви можете префіксувати structім'я за ключовим словом structкожного разу, коли на нього посилаєтесь, простори імен об'єднуються, і тому вищевказаний фрагмент C недійсний. З іншого боку, C ++ спеціально робить виняток, щоб дозволити типу та typedef для цього типу мати однакове ім’я (очевидно, без ефекту), щоб дозволити використання typedefтрюку, незмінного від C.


1
Ваш останній приклад невірний C: три мітки ( struct, unionі enum) один і ті ж простір імен. Кращим прикладом може бутиstruct foo { ... }; typedef enum { ... } foo;
знімок

@schot: ви, звичайно, праві, дякую за виправлення. Оновлено.
Павло Мінаєв

8

Це також залежить від того, який різновид C ви використовуєте. Stroustrup зробив C ++ максимально сумісним і не більше сумісним зі стандартами ANSI 1989 та 1990 р. ISO, а версія 1995 року нічого не змінила. Комітет C пішов дещо в іншому напрямку зі стандартом 1999 року, а комітет C ++ змінив наступний стандарт C ++ (можливо, вийшов наступного року або близько того), щоб відповідати деяким змінам.

Stroustrup перераховує несумісність із C90 / C95 у Додатку B.2 до "Мова програмування C ++", Спеціальне видання (яке є 3-м виданням з деяким доданим матеріалом):

'a'є intв C, a charв C ++.

Розмір перерахунку знаходиться intв C, не обов'язково в C ++.

C ++ має //коментарі до кінця рядка, C - ні (хоча це звичайне розширення).

У C ++ struct foo {визначення вкладається fooу глобальний простір імен, тоді як у C воно має бути позначене як struct foo. Це дозволяє structвизначити тенізацію імені у зовнішній області і має кілька інших наслідків. Крім того, C дозволяє розширювати сферу для structвизначень і дозволяє їх у зворотному описі типу та аргументу.

C ++ загалом суєтніше щодо типів. Це не дозволить призначити ціле число числу enum, а void *об'єкти не можуть бути призначені іншим типам вказівників без набору. У C можна надати ініціалізатор перебільшення ( char name[5] = "David"де C відкине проміжний нульовий символ).

C89 дозволяється неявним intу багатьох контекстах, а C ++ - ні. Це означає, що всі функції повинні бути оголошені в C ++, тоді як у C89 це часто можна було отримати, припускаючи intвсе, що застосовується в декларації функції.

У C можна перейти з-за меж блоку всередину за допомогою оператора з міткою. У C ++ це заборонено, якщо він пропускає ініціалізацію.

C є більш ліберальним у зовнішній зв'язці. У C глобальна constзмінна неявно extern, і це не вірно в C ++. C дозволяє глобальному об'єкту даних кілька разів оголошуватися без extern, але це не відповідає дійсності в C ++.

Багато ключових слів C ++ не є ключовими словами на C, або #defined у стандартних заголовках C.

Є також деякі старі функції C, які вже не вважаються хорошим стилем. В C ви можете оголосити функцію з визначеннями аргументів після списку аргументів. У C декларація як int foo()означає, що foo()може приймати будь-яку кількість аргументів будь-якого типу, тоді як у C ++ це еквівалентно int foo(void).

Це, здається, охоплює все від Stroustrup.


Не будемо забувати той факт, що в C ви повинні оголосити змінні на початку області (тобто, відразу після відкриття дужки), тоді як C ++ дозволяє декларування змінних у будь-якому місці.
RobH

4
Однак це те, що C ++ може зробити, що C не може. Я думаю, ми дивимось на те, що ти можеш робити на C, але не на C ++.
Девід Торнлі

2
@RobH: Це справедливо для C89, але не для C99.
jamesdlin

6

Якщо ви використовуєте gcc, ви можете скористатись попередженням, -Wc++-compatщоб попередити про код C, який певним чином є сумнівним у C ++. Наразі його використовують у самому gcc, а останнім часом він значно покращився (можливо, спробуйте нічну версію, щоб отримати найкраще, що можна).

(Це абсолютно не відповідає на питання, але людям це може сподобатися).


1
Я думав, що ніколи не підтримаю відповідь без відповіді
eharo2

4

Найбільшою різницею, на яку я думаю, є те, що це дійсний вихідний файл C:

int main()
{
    foo();
}

Зауважте, що я fooніде не декларував .

Окрім мовних відмінностей, C ++ також вносить деякі зміни в бібліотеку, успадковану від C, наприклад, деякі функції повертаються const char *замість char *.


Правильно, прототипи в C не потрібні, але зазвичай вважається поганою практикою їх не використовувати.
Роберт Гембл

1
Слід s,C,C89,зауважити, що це недійсний вихідний файл C99.
Йоханнес Шауб - лібл

Це неправда або просто застаріла в C99?
jalf

2
@jalf C99 проектує документи на зміни C89 і включає як "видалити неявний int", так і "видалити неявну функцію оголошення".
Йоханнес Шауб - ліб


2

Низка відповідей тут охоплює різниці в синтаксисі, які можуть спричинити збій компіляторів C ++ у вихідному коді C89 (або C99). Однак є деякі тонкі мовні відмінності, які є законними для обох мов, але це може спричинити різну поведінку. sizeof (char)Різниця , що Навин згадується один з прикладів, але написати програму , яка буде друкувати «C» , якщо скомпільовано як (ANSI) C програми, і «C ++» , якщо скомпільовано як ++ програм C перераховані деякі інші.


-2

Компілятори C зазвичай дозволяють вирізати невеликий кут, який C ++ не робить. C ++ набагато суворіший за C. І взагалі деякі з цих відмінностей залежать від компілятора. g ++ дозволяє деякі речі, наприклад, компілятор Intel C ++. Навіть досить добре написаний код C не компілюється із сучасним компілятором C ++.


-2

Ви не можете порівнювати мови лише за синтаксисом. Якщо ви це зробите, можливо, ви можете бачити C як підмножину C ++. На мою думку, того, що C ++ є OO (а C - ні), достатньо, щоб сказати, що C і C ++ - це різні мови.


2
Неправильно. C ++ - це не тільки ОО. Ви можете подумати, що C ++ щось на кшталт "C ++ = C + OO + загальне програмування + бонуси". По-іншому, "C & C ++ ~ = C", де ~ = означає майже рівний.
paercebal
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.