许多初学者都以为 C 是 C++ 的子集,其实这种观点是不正确的。C++ 之父 Bjarne Stroustrup (简称 B.S)在其 FAQ 上解答了这个问题。
C 是 C++ 的子集吗?
严格按照数学上的定义来说,C 不是 C++ 的子集。有些程序在 C 里面是合法的,但在 C++ 里却是不合法的;甚至有些编写代码的方式在 C 和 C++ 中有不同的含义。然而,C++ 支持 C 所支持的全部编程技巧。任何 C 程序都能被 C++ 用基本相同的方法写出来,并且运行效率和空间效率都一样。把数万行 ANSI C 代码转换成 C 风格的 C++ 代码,通常只需要几个小时。因此,C++ 是 ANSI C 的超集程度和 ANSI C 是 K&R C 的超集程度以及 ISO C++ 是 1985 年的 C++ 的超集程度差不多。
编写风格好的 C 程序通常会是合法的 C++ 程序。例如,Kernighan 和 Ritchie 合著的《C 程序设计语言(第二版)》中的所有例子都是 C++ 程序。
C/C++ 兼容性问题的一些例子:
int main()
{
double sq2 = sqrt(2); /* 不是 C++:调用了未经声明的函数 */
int s = sizeof('a'); /* 隐蔽的区别:C++ 中是 1,而 C 中却是 sizeof(int) */
}
调用未经声明的函数在 C 里是不良风格,而在 C++ 里是非法的。同样的情况还有,传递参数给一个没有在其声明中列出参数类型的函数:
void f(); /* 没有注明参数类型 */
void g()
{
f(2); /* C 中是不良风格。C++ 中不合法 */
}
C 里面,void* 可以隐式转换为任何指针类型,并且堆空间分配通常是通过 malloc() 进行的,无法检查是否已经分配了足够的内存:
void* malloc(size_t);
void f(int n)
{
int* p = malloc(n*sizeof(char)); /* C++ 中非法。C++ 使用 new 分配堆空间 */
char c;
void* pv = &c;
int* pi = pv; /* 隐式转换 void* 为 int*。C++ 中非法 */
}
请注意,隐式转换 void* 为 int* 引起了潜在的数据对齐错误。请参阅 C++ 中 void* 和 malloc() 的代替品。
把 C 代码转换成 C++ 时,请紧记 C++ 的关键字比 C 多:
int class = 2; /* C 中合法。C++ 中是语法错误 */
int virtual = 3; /* C 中合法。C++ 中是语法错误 */
除了少数例外,如上面所述的例子(以及 C++ 标准和 C++ 程序设计语言第三版附录 B 里详细列举的例子),C++ 是 C 的超集。(附录 B 可以通过下载获取)
请注意,“C”在以上段落中指的是经典 C 和 C89。C++ 不是 C99 的后裔;C++ 和 C99 是兄弟。C99 引入了一些新特性,造成 C/C++ 的不兼容性进一步增大。这里有一篇 C++98 和 C99 的不同点的描述。
原文地址:http://www.research.att.com/~bs/bs_faq.html#C-is-subset
================================
antigloss 注:原文说“Kernighan 和 Ritchie 合著的《C 程序设计语言(第二版)》(简称 K&R)中的所有例子都是 C++ 程序”,我对此有不同看法。C++ 要求函数必须显式注明其返回值类型,而 K&R 中所有的 main 函数都没有注明返回值类型,这显然不是合法的 C++ 代码。或许 B.S 指的是标准前的 C++ 吧。标准前的 C++ 是允许不显式注明函数返回值类型的,如果省略返回值类型,则默认为 int。而且,C++ 中的标准头文件已经不用 .h 了,但是 K&R 中用的都是 .h。当然,C 中也只能用 .h。同样,标准前的 C++ 用的也是 .h。就此,我已发了一封 e-mail 给他老人家,得到他的回复如下:
> I wrote this mail to ask you a question on an article at your FAQ: Is C a
>subset of C++? In this article, you wrote "every example in Kernighan &
>Ritchie: 'The C Programming Language (2nd Edition)' is also a C++ program",
>which is what I doubt about. In C++, every function must explicitly write
>down its return type. But in K&R, none of the main function had its return
>type written. So those programs shouldn't be C++ progroms. I know in K&R
>C, if return type is omitted, then `int' is implied, so does pre-standard
>C++.
and that was allowed in C++ at the time. You could then say that K&R2 is neither
C nor C++, but I find that a bit pedantic. Especially as C and C++ changed in
exactly the same way.
> Also, in K&R, each header uses .h postfix which is not used in C++ but
>used in pre-standard C++.
but the .h form is allowed for the C headers in C++, even today.
大意为:
>C++ 要求函数必须显式注明其返回值类型,而 K&R 中所有的 main 函数都没有注明返回值类型,
>这显然不是合法的 C++ 代码。标准前的 C++ 允许不显式注明函数返回值类型,如果省略返回值类型,
>则默认为 int。
那时的 C++ 也允许这种做法。你可以说 K&R2 既不是 C 也不是 C++,但我觉得这样有点咬文嚼字了。尤其是,C 和 C++ 都朝同样的方向作了改变。
>C++ 中的标准头文件已经不用 .h 了,但是 K&R 中用的都是 .h。同样,标准前的 C++ 用的也是 .h。
但 C++ 仍然允许 C 头文件使用 .h 形式,甚至今天。
本文版权归 蚂蚁的 C/C++ 标准编程 以及 作者 Bjarne Stroustrup 翻译:antigloss 共同所有,转载请注明原作者和出处。谢谢。