Где C не подмножество С++?

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

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

Каковы некоторые случаи, когда код будет скомпилирован в C, но не С++?

Ответ 1

Если вы сравниваете C89 с C++, то вот несколько вещей

Нет предварительных определений в С++

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

int [] и int [N] несовместимы (нет совместимых типов в С++)

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

Вложенная структура имеет класс-область в С++

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);

Ответ 2

В C, sizeof('a') равно sizeof(int).

В С++ sizeof('a') равен sizeof(char).

Ответ 3

У С++ есть и новые ключевые слова. Ниже приведен допустимый код C, но он не будет скомпилирован под С++:

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

Ответ 4

Есть много вещей. Просто простой пример (этого должно быть достаточно, чтобы доказать, что C не является надлежащим подмножеством С++):

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

должен компилироваться в C, но не в С++.

Ответ 5

В С++, если вы объявляете 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;

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

Ответ 6

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

Stroustrup перечисляет несовместимости с C90/C95 в Приложении B.2 "Язык программирования С++", Special Edition (который является третьим изданием с некоторыми дополнительными материалами):

'a' является int в C, a char в С++.

Размер перечисления int в C, не обязательно в С++.

С++ имеет // комментарии к концу строки, C не является (хотя и является общим расширением).

В С++ определение struct foo { помещает foo в глобальное пространство имен, тогда как в C оно должно называться struct foo. Это позволяет определить struct тень имени во внешней области и имеет несколько других последствий. Кроме того, C позволяет расширить область определения struct и позволяет им в объявлениях типа возвращаемого типа и типа аргументов.

С++ более суетливо относится к типам вообще. Он не позволит назначать целое число для объектов enum, а void * нельзя назначать другим типам указателей без трансляции. В C можно предоставить перекрывающий инициализатор (char name[5] = "David", где C отбрасывает конечный нулевой символ).

C89 допускает неявный int во многих контекстах, а С++ - нет. Это означает, что все функции должны быть объявлены в С++, в то время как в C89 часто можно было обойтись с предположением int для всего, что применимо в объявлении функции.

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

C более либеральна во внешней связи. В C глобальная переменная const неявно extern, и это не верно в С++. C позволяет объявлять глобальный объект данных несколько раз без extern, но это не так на С++.

Многие ключевые слова С++ не являются ключевыми словами в C или являются #define d в стандартных заголовках C.

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

Это похоже на все, что от Страустрапа.

Ответ 7

#include <stdio.h>

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

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

См. также запись в С++ FAQ.

Ответ 8

Единственное самое большое различие, которое я думаю, это то, что это действительный исходный файл C:

int main()
{
    foo();
}

Обратите внимание, что я нигде не объявлял foo.

Помимо языковых различий, С++ также вносит некоторые изменения в библиотеку, которую он унаследовал от C, например. некоторые функции возвращают const char * вместо char *.

Ответ 9

Если вы используете gcc, вы можете использовать предупреждение -Wc++-compat, чтобы дать вам предупреждения о C-коде, который так или иначе сомневается в С++. В настоящее время он используется в самой gcc, и в последнее время он стал намного лучше (возможно, попробуйте ночную версию, чтобы получить все возможное).

(Это не дает строгого ответа на вопрос, но людям это может понравиться).

Ответ 10

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

Ответ 11

Компиляторы

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

Ответ 12

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