Где C не является подмножеством C ++? [закрыто]

116

Я читал во многих книгах, что C - это подмножество C ++.

В некоторых книгах говорится, что C - это подмножество C ++, за исключением мелких деталей .

В каких случаях код компилируется на C, но не на C ++?

n00ki3
источник

Ответы:

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);
Йоханнес Шауб - litb
источник
@mehrdad, спасибо. oO не знал, что нужно создать переменную уже при объявлении вложенной структуры в C. Исправлено.
Йоханнес Шауб - лит
3
Есть еще один (бесполезный) C89 для C ++: typedef;это законный TU в C, но не в C ++.
Flexo
Обратите внимание, что auto a;это действительно в последней версии стандарта C ++.
fuz
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'это файл 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*.
Mehrdad Afshari
8
Длинный ответ: возвращается malloc void *, который в C может быть назначен любому типу указателя, а C ++ не может быть назначен любому другому типу указателя.
Дэниел Эрвикер,
5
Imagist: компилятор C в соответствии со стандартом ANSI C89 не должен жаловаться.
Mehrdad Afshari
7
Это законно C. Приведение не нужно, можно ошибиться и скрывает отсутствие включения <stdlib.h>. Я считаю заявление Мехрдада правильным способом написать его на C.
Дэвид Торнли
16
@Imagist: Обычно я слышу обратное от программистов на C. Они считают плохим стилем добавлять слепок, так как это может скрыть ошибки. Хороший код C не использует приведение типов.
jalf
16

В C ++, если вы объявляете 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
@schot: вы конечно правы, спасибо за поправку. Обновлено.
Павел Минаев
8

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

Страуструп перечисляет несовместимость с C90 / C95 в Приложении B.2 «Язык программирования C ++», Special Edition (это 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 или содержатся #defineв стандартных заголовках C.

Есть также некоторые старые особенности C, которые больше не считаются хорошим стилем. В C вы можете объявить функцию с определениями аргументов после списка аргументов. В C такое объявление int foo()означает, чтоfoo() может принимать любое количество аргументов любого типа, а в C ++ оно эквивалентно int foo(void).

Похоже, это касается всего, что касается Страуструпа.

Дэвид Торнли
источник
Не будем забывать тот факт, что в C вы должны объявлять переменные в начале области видимости (т. Е. Сразу после открывающей скобки), тогда как C ++ допускает объявление переменных где угодно.
RobH
4
Однако 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 перечислены некоторые другие.

jamesdlin
источник
-2

Компиляторы C обычно допускали небольшую обрезку углов, в отличие от C ++. C ++ намного строже, чем C. И, как правило, некоторые из этих различий зависят от компилятора. g ++ допускает некоторые вещи, которые, например, не позволяет компилятору Intel C ++. Даже хорошо написанный код C не будет компилироваться с современным компилятором C ++.

xcramps
источник
-2

Вы не можете сравнивать языки только по синтаксису. Если вы это сделаете, возможно, вы увидите C как подмножество C ++. На мой взгляд, того факта, что C ++ - объектно ориентированный (а C - нет), достаточно, чтобы сказать, что C и C ++ - разные языки.

fnurglewitz
источник
2
Неправильно. C ++ - это не только объектно-ориентированный подход. Вы можете думать о C ++ как о «C ++ = C + OO + общее программирование + бонусы». Другими словами, «C & C ++ ~ = C», где ~ = означает почти равный.
paercebal