我在很多书中读到 C 是 C + + 的一个子集。
有些书说 C 是 C + + 除了一些小细节的子集。
什么情况下代码只能在 C 语言中编译,而不能在 C + + 中编译?
有很多事情。只是一个简单的例子(它应该足以证明 C 不是 C + + 的正确子集) :
int* test = malloc(100 * sizeof(int));
应该用 C 语言编译,而不是用 C + + 。
在 C 中,sizeof('a')等于 sizeof(int)。
sizeof('a')
sizeof(int)
在 C + + 中,sizeof('a')等于 sizeof(char)。
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。
foo
除了语言上的差异,C + + 还对继承自 C 的库进行了一些修改,例如一些函数返回 const char *而不是 char *。
const char *
char *
在 C + + 中,如果声明一个 struct、 union或 enum,则可以立即访问它的名称,而不需要任何限定符:
struct
union
enum
struct foo { ... }; foo x; // declare variable
在 C 语言中,这是行不通的,因为这样声明的类型存在于它们各自不同的名称空间中:
struct foo { ... }; struct foo x; // declare variable
注意第二行中出现了 struct。你必须对 union和 enum做同样的事情(使用它们各自的关键字) ,或者使用 typedef技巧:
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 + + 编译器编译。
如果你比较 C89和 C++,这里有一些事情
C89
C++
int n; int n; // ill-formed: n already defined
int a[1]; int (*ap)[] = &a; // ill-formed: a does not have type int[]
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)
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。
'a'
int
char
枚举的大小在 C 中是 int,而在 C + + 中不一定是 int。
C + + 在行尾有 //注释,而 C 没有(尽管它是一个常见的扩展)。
//
在 C + + 中,struct foo {定义将 foo放入全局名称空间,而在 C 中,它必须被称为 struct foo。这允许 struct定义在外部作用域中隐藏名称,并且还有其他一些后果。此外,C 允许更大范围的 struct定义,并允许它们在返回类型和参数类型声明。
struct foo {
struct foo
一般来说,C + + 对类型比较挑剔。它不允许将整数分配给 enum,而且如果没有强制转换,则不能将 void *对象分配给其他指针类型。在 C 中,可以提供一个超大的初始值设定项(char name[5] = "David",其中 C 将丢弃尾随的空字符)。
void *
char name[5] = "David"
C89允许在许多上下文中使用隐式 int,而 C + + 不允许。这意味着所有函数都必须在 C + + 中声明,而在 C89中,通常可以假设函数声明中适用的所有函数都是 int。
在 C 语言中,可以使用带标签的语句从块的外部跳到块的内部。在 C + + 中,如果跳过初始化,则不允许这样做。
C 语言在外部连接方面更加自由。在 C 中,全局 const变量是隐式的 extern,而在 C + + 中则不是这样。C 允许在没有 extern的情况下多次声明一个全局数据对象,但是在 C + + 中不是这样。
const
extern
许多 C + + 关键字在 C 中不是关键字,或者在标准 C 头中是 #defined。
#define
还有一些 C 的旧特性不再被认为是好的风格。在 C 语言中,可以使用参数定义在参数列表之后声明函数。在 C 语言中,像 int foo()这样的声明意味着 foo()可以接受任意数量的任意类型的参数,而在 C + + 中,它等价于 int foo(void)。
int foo()
foo()
int foo(void)
这似乎涵盖了 Stroustrup 的一切。
如果您使用 gcc,您可以使用警告 -Wc++-compat给您关于 C 代码的警告,这在某种程度上在 C + + 中是可疑的。它目前在 gcc 中使用,并且最近变得更好了(也许可以尝试一个夜间版本,以获得最好的效果)。
-Wc++-compat
(严格来说,这并不能回答这个问题,但人们可能会喜欢它)。
这里的许多答案涵盖了会导致 C + + 编译器在 C89(或 C99)源代码上失败的语法差异。然而,在两种语言中都存在一些微妙的语言差异,这些差异在两种语言中都是合法的,但是会产生不同的行为。Naveen 提到的 sizeof (char)差异就是一个例子,但是 编写一个程序,如果编译为(ANSI) C 程序,则打印“ C”,如果编译为 C + + 程序,则打印“ C + +”列出了其他一些例子。
sizeof (char)