哪里 C 不是 C + + 的子集?

我在很多书中读到 C 是 C + + 的一个子集。

有些书说 C 是 C + + 除了一些小细节的子集。

什么情况下代码只能在 C 语言中编译,而不能在 C + + 中编译?

29595 次浏览

有很多事情。只是一个简单的例子(它应该足以证明 C 不是 C + + 的正确子集) :

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

应该用 C 语言编译,而不是用 C + + 。

在 C 中,sizeof('a')等于 sizeof(int)

在 C + + 中,sizeof('a')等于 sizeof(char)

#include <stdio.h>


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


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

参见 C + + 常见问题解答条目

C + + 也有新的关键字。以下是有效的 C 代码,但不能在 C + + 下编译:

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

我认为最大的区别在于这是一个有效的 C 源文件:

int main()
{
foo();
}

注意,我没有在任何地方声明 foo

除了语言上的差异,C + + 还对继承自 C 的库进行了一些修改,例如一些函数返回 const char *而不是 char *

在 C + + 中,如果声明一个 structunionenum,则可以立即访问它的名称,而不需要任何限定符:

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

在 C 语言中,这是行不通的,因为这样声明的类型存在于它们各自不同的名称空间中:

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

注意第二行中出现了 struct。你必须对 unionenum做同样的事情(使用它们各自的关键字) ,或者使用 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 具有相同的名称(显然没有效果) ,以允许使用与 C 不同的 typedef技巧。

C 编译器通常允许一些 C + + 不允许的切入点。C + + 要比 C 严格得多,而且一般来说,这些差异中的一些是依赖于编译器的。例如,g + + 允许一些 Intel C++编译器不允许的事情。即使编写得相当好的 C 代码也不能用现代 C + + 编译器编译。

如果你比较 C89C++,这里有一些事情

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 + + 中具有 class-scope

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

这也取决于你使用的 C 的种类。Stroustrup 使 C + + 与1989年的 ANSI 和1990年的 ISO 标准尽可能兼容,而且不再兼容,1995年的版本也没有改变任何东西。C 委员会与1999年的标准有些不同的方向,C + + 委员会已经改变了下一个 C + + 标准(可能在明年左右发布) ,以适应一些变化。

Stroustrup 在“ C++程式语言”的附录 b 2中列出了与 C90/c95的不兼容性,特别版(这是第3版,添加了一些材料) :

'a'是 C 中的 int,C + + 中的 char

枚举的大小在 C 中是 int,而在 C + + 中不一定是 int

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 中不是关键字,或者在标准 C 头中是 #defined。

还有一些 C 的旧特性不再被认为是好的风格。在 C 语言中,可以使用参数定义在参数列表之后声明函数。在 C 语言中,像 int foo()这样的声明意味着 foo()可以接受任意数量的任意类型的参数,而在 C + + 中,它等价于 int foo(void)

这似乎涵盖了 Stroustrup 的一切。

如果您使用 gcc,您可以使用警告 -Wc++-compat给您关于 C 代码的警告,这在某种程度上在 C + + 中是可疑的。它目前在 gcc 中使用,并且最近变得更好了(也许可以尝试一个夜间版本,以获得最好的效果)。

(严格来说,这并不能回答这个问题,但人们可能会喜欢它)。

这里的许多答案涵盖了会导致 C + + 编译器在 C89(或 C99)源代码上失败的语法差异。然而,在两种语言中都存在一些微妙的语言差异,这些差异在两种语言中都是合法的,但是会产生不同的行为。Naveen 提到的 sizeof (char)差异就是一个例子,但是 编写一个程序,如果编译为(ANSI) C 程序,则打印“ C”,如果编译为 C + + 程序,则打印“ C + +”列出了其他一些例子。