注意! 本篇内容来自Wikipedia,中文版节选为User:Ining Chien即用户[1]所翻译,英文版为英文维基百科内容。
C语言和C++的关系十分密切,但是也有许多显著的差异。C++标准起源于早期C标准, 并被设计为与当时的C语言在源代码编写和链接方面很大程度上兼容.[1][2] 因此,两种语言的开发工具(例如IDE和编译器)通常被集成到单个产品中,程序员可以自己选择编写的是C还是C ++,开发工具通常会根据程序员的选择使用不同的编译器和链接器或不同的库。
即便如此,C并不是C++的子集[3], 一般的C语言代码不经修改很难被一些严格符合C++标准的C++编译器成功编译;同样,几乎所有的C++代码都无法被C语言编译器编译。 在这篇文章中,我们主要讨论的是它们在公共部分的差异,比如在C语言中合法的代码到了C++中成为了不合法的代码,或一段代码在C和C++中表现出不同的行为。
C++的创始人Bjarne Stroustrup建议[4] C和C++应该尽可能减小差异,以提高这两种语言的兼容性; 而另一些人则认为C和C++毕竟是两种不同的语言——虽然C++起源于C——因此它们之间的兼容性并不是那么重要。 而ANSI的看法:“我们赞同保持C与C++的最大公共子集原则”,同时“保持它们的差别,使这两种语言继续独立发展”,“......委员会希望C++成为重要的和强有力的语言”。[5][6]
截止到[[C++20]]和C2x,C++不支持部分C语言特性,如变长数组,原生复数支持和restrict
Template:Link-en。另一方面,与C89相比,C99通过合并C ++功能(例如//
注释,允许声明出现在代码中而不只是在函数头)减少了一些其他不兼容性。
C++较C语言有更严格的类型转换和初始化规则[1][7] , 因此一些在C语言里合法的语句在C++里是不合法的。ISO C++附录C.1列出了这些区别。[8]
void*
指针赋值给任何类型的指针而无需强制转换,而C ++则不允许;这个习惯用法经常出现在使用malloc
管理内存的C代码中,[9] 或POSIX线程库的上下文传递以及其他涉及回调的框架。例如,下面这个例子在C语言中是可行的,但在C++中不允许:<syntaxhighlight lang="c">
void *ptr; /*从void *到int *的隐式转换*/ int *i = ptr;
</syntaxhighlight>
<syntaxhighlight lang="c">
int *j = malloc(5 * sizeof *j); /*从void *到int *的隐式转换 */
</syntaxhighlight>
<syntaxhighlight lang="c++">
void *ptr; int *i = (int *)ptr; int *j = (int *)malloc(5 * sizeof *j);
</syntaxhighlight>
C++中提供了其它方法来实现指针类型转换。C++不推荐继续使用老式类型转换。老式类型转换在形式上来说不是特别清晰,容易被忽略。[12]。
<syntaxhighlight lang="c++">
void *ptr; auto i = reinterpret_cast<int *>(ptr); auto j = new int[5];
</syntaxhighlight>
strchr
在C语言中的声明为Template:Qcode,而在C++中则有一个重载函数为const char *strchr(const char *)
。<syntaxhighlight lang="c++">
const int var1; const int var2 = 1; </syntaxhighlight>第一行代码在C语言中是允许的(在某些编译器中可能会报告一个“Warning”),但在C++中会报错;第二行代码在C和C++中都是合法的。
<syntaxhighlight lang="c">
void fn(void) {
goto flack; int i = 1;
flack:
;
}
</syntaxhighlight>
Template:ProgLangCompare The C and C++ programming languages are closely related but have many significant differences. C++ began as a fork of an early, pre-standardized C, and was designed to be mostly source-and-link compatible with C compilers of the time.[1][14] Due to this, development tools for the two languages (such as IDEs and compilers) are often integrated into a single product, with the programmer able to specify C or C++ as their source language.
However, C is not a subset of C++,[3] and nontrivial C programs will not compile as C++ code without modification. Likewise, C++ introduces many features that are not available in C and in practice almost all code written in C++ is not conforming C code. This article, however, focuses on differences that cause conforming C code to be ill-formed C++ code, or to be conforming/well-formed in both languages but to behave differently in C and C++.
Bjarne Stroustrup, the creator of C++, has suggested[15] that the incompatibilities between C and C++ should be reduced as much as possible in order to maximize inter-operability between the two languages. Others have argued that since C and C++ are two different languages, compatibility between them is useful but not vital; according to this camp, efforts to reduce incompatibility should not hinder attempts to improve each language in isolation. The official rationale for the 1999 C standard (C99) "endorse[d] the principle of maintaining the largest common subset" between C and C++ "while maintaining a distinction between them and allowing them to evolve separately", and stated that the authors were "content to let C++ be the big and ambitious language."[16]
Several additions of C99 are not supported in the current C++ standard or conflicted with C++ features, such as variable-length arrays, native complex number types and the restrict
type qualifier. On the other hand, C99 reduced some other incompatibilities compared with C89 by incorporating C++ features such as //
comments and mixed declarations and code.[17]
C++ enforces stricter typing rules (no implicit violations of the static type system[1]), and initialization requirements (compile-time enforcement that in-scope variables do not have initialization subverted)[18] than C, and so some valid C code is disallowed in C++. A rationale for these is provided in Annex C.1 of the ISO C++ standard.[19]
void*
pointer to be assigned to any pointer type without a cast, while C++ does not; this idiom appears often in C code using malloc
memory allocation,[9] or in the passing of context pointers to the POSIX pthreads API, and other frameworks involving callbacks. For example, the following is valid in C but not C++:<syntaxhighlight lang="c">void *ptr; /* Implicit conversion from void* to int* */ int *i = ptr; </syntaxhighlight>
<syntaxhighlight lang="c">int *j = malloc(5 * sizeof *j); /* Implicit conversion from void* to int* */</syntaxhighlight>
<syntaxhighlight lang="c++"> void *ptr; int *i = (int *)ptr; int *j = (int *)malloc(5 * sizeof *j); </syntaxhighlight>
Though C++ favors this:[22]Template:Better source needed
<syntaxhighlight lang="c++"> void *ptr; auto i = reinterpret_cast<int *>(ptr); auto j = new int[5]; </syntaxhighlight>
const
type qualifiers, e.g. strchr
returns char*
in C, while C++ acts as if there were two overloaded functions const char *strchr(const char *)
and a char *strchr(char *)
.enum
enumerators) are always of type int
in C, whereas they are distinct types in C++ and may have a size different from that of int
. C++11 allows the programmer to use custom integer types for the values of an enum.const
variable must be initialized; in C this is not necessary.<syntaxhighlight lang="c"> void fn(void) {
goto flack; int i = 1;
flack:
;
} </syntaxhighlight>
longjmp()
results in undefined behaviour in C++ if the jumped-over stack frames include objects with nontrivial destructors.[23] The C++ implementation is free to define the behaviour such that destructors would be called. However, this would preclude some uses of longjmp() which would otherwise be valid, such as implementation of threads or coroutines by longjmping between separate call stacks - when jumping from the lower to the upper call stack in global address space, destructors would be called for every object in the lower call stack. No such issue exists in C.<ref>
标签;name属性“overview”使用不同内容定义了多次
|df=
(帮助); 已忽略未知参数|url-status=
(帮助)
|df=
(帮助); 已忽略未知参数|url-status=
(帮助)
|df=
(帮助); 已忽略未知参数|url-status=
(帮助)
|df=
(帮助); 已忽略未知参数|url-status=
(帮助) ("It is invalid to jump past a declaration with explicit or implicit initializer (except across entire block not entered). … With this simple compile-time rule, C++ assures that if an initialized variable is in scope, then it has assuredly been initialized.")
|df=
(帮助); 已忽略未知参数|url-status=
(帮助)
|df=
(帮助); 已忽略未知参数|url-status=
(帮助)
|df=
(帮助); 已忽略未知参数|url-status=
(帮助)
|df=
(帮助); 已忽略未知参数|url-status=
(帮助)