C(99)和C ++(11)之间有什么不兼容的区别?

时间:2012-05-05 11:19:44

标签: c++ c c++11 c99

这个问题是由一个post by Herb Sutter的回复触发的,他在那里解释了MS不支持/制作C99编译器的决定,但只是采用了C ++中的C(99)特性(11)无论如何标准。

一个commenter replied

  

(...)C很重要,值得至少注意一点。

     

有很多现有的代码是有效的C但不是   有效的C ++。该代码不太可能被重写(...)

由于我只用MS C ++编程,我真的不知道“纯粹的”C,即我没有准备好了解C ++的细节 - 我正在使用的语言不在C(99)和我有一些线索,其中一些C99代码在C ++编译器中无法正常工作。

请注意,我知道仅C99 restrict关键字对我来说似乎具有非常狭窄的应用程序和关于可变长度数组(我不确定它有多广泛)或者重要的是。)

另外,我非常感兴趣是否存在任何重要的语义差异或陷阱,即C(99)代码将在C ++(11)下编译但使用C ++做一些不同的事情编译器比用C编译器。


快速链接:答案中的外部资源:

4 个答案:

答案 0 :(得分:29)

有许多不兼容性已经存在多年(C90或更早),以及C99和C11中的一些非常好的功能。这些都是我的头脑。

// Valid C
int *array = malloc(sizeof(*array) * n);

// Valid C and valid C++, extra typing, it's always extra typing...
int *array = (int *) malloc(sizeof(*array) * n);

// Valid C++
int *array = new int[n];

C99很好,各地的C程序员都应该使用它

C99的新功能非常适合一般编程。 VLA和restrict不是(在我看来)针对一般用途,但主要是为了将FORTRAN和数字程序员带到C(尽管restrict帮助自动向量)。由于任何使用restrict的符合程序仍然会以完全相同的方式工作(但可能不会那么快),如果您在文件顶部#define restrict,那么这并不是什么大问题。在野外,VLA看起来非常罕见。

灵活的数组成员可以很好。请注意,这些与可变长度数组不同!人们多年来一直在使用这个技巧,但官方支持意味着更少的输入,它也允许我们在编译时制作常量。 (旧的方法是使用大小为1的数组,但是计算分配大小真是太麻烦了。)

struct lenstr {
    unsigned length;
    char data[];
};
// compile time constant
const struct lenstr hello = { 12, "hello, world" };

指定初始值设定项。节省大量输入内容。

struct my_struct { int a; char *b; int c; const char *d; };
struct my_struct x = {
    .a = 15,
    .d = "hello"
    // implicitly sets b = NULL and c = 0
};
int hex_digits[256] = { ['0'] = 0, ['1'] = 1, ['2'] = 2, /* etc */ ['f'] = 15 };

inline关键字的行为有所不同,您可以选择哪个翻译单元通过向该单元添加extern声明来获取内联声明的函数的非内联版本。

复合文字。

struct point { float x; float y; };
struct point xy_from_polar(float r, float angle)
{
    return (struct point) { cosf(angle) * r, sinf(angle) * r };
}

snprintf函数可能是我在C中最有用的十大函数库。它不仅缺少C ++,而且MSVC运行时只提供一个名为{的函数{1}},不能保证在字符串中添加NUL终止符。_snprintf在C ++ 11中,但在MSVC C运行时中仍然明显不存在。)

匿名结构和联盟 (C11,但永远是GCC扩展)(匿名联盟显然是在C ++ 03中,在C模式下没有MSVC支持):< / p>

snprintf

正如您所看到的,许多这些功能只会为您节省大量的输入(复合文字),或使程序更容易调试(灵活的数组成员),更容易避免错误(指定初始化器/忘记初始化结构字段)。这些并没有太大的变化。

对于语义差异,我确定别名规则是不同的,但是现在大多数编译器都很宽容我不知道你是如何构建一个测试用例来演示的。每个人都会遇到的C和C ++之间的差异是旧的struct my_value { int type; union { int as_int; double as_double; }; // no field name! }; 表达式,对于C ++,它总是1,但在32位C系统上通常是4。但无论如何,没有人关心sizeof('a')。但是,C99标准中有一些保证可以编纂现有做法。

采取以下代码。它使用一种常见的技巧来定义C中的联合类型而不浪费额外的存储空间。我认为这是语义上有效的C99而我认为这是语义上可疑的C ++,但我可能错了。

sizeof('a')

这很遗憾。 MSVC代码生成器很好,太糟糕了,没有C99前端。

答案 1 :(得分:26)

如果从C和C ++的公共子集开始,有时称为干净C(不完全是C90),则必须考虑3种类型的不兼容性:

  1. 使合法C非法C ++的其他C ++特性

    这方面的例子是C ++关键字,可以用作C中的标识符或转换,这些关键字隐含在C中但需要在C ++中进行显式转换。

    这可能是微软仍然提供C前端的主要原因:否则,不能编译为C ++的遗留代码将不得不重写。

  2. 不属于C ++的其他C功能

    在C ++分叉后,C语言并没有停止发展。一些示例是可变长度数组,指定初始值设定项和restrict。这些功能非常方便,但不是任何C ++标准的一部分,其中一些可能永远不会出现。

  3. C和C ++中可用但具有不同语义的功能

    这方面的一个示例是const对象或inline函数的链接。

  4. C99和C ++ 98 can be found here之间的不兼容性列表(Mat已经提到过)。

    虽然C ++ 11和C11在某些方面越来越接近(变量宏现在在C ++中可用,变长数组现在是可选的C语言特性),但不兼容性列表也在增长(例如,通用选择) C和C ++中的auto类型说明符。)

    顺便说一句,虽然微软为放弃C(这不是最近的C)做出了一些热情,但据我所知,开源社区中没有人真正采取措施对此采取措施:通过C-to-C ++编译器提供现代C的许多功能是非常可能的,特别是如果你考虑some of them are trivial to implement。这实际上现在可以使用Comeau C / C ++,它支持C99。

    然而,这并不是一个迫切的问题:就个人而言,我对在Windows上使用GCC和Clang非常感到满意,并且还有MSVC的专有替代品,例如Pelles C或Intel的编译器。

答案 2 :(得分:2)

在C ++中,设置union的一个成员并访问另一个成员的值是未定义的行为,而在C99中它没有未定义。

维基百科page上列出了许多其他差异。

答案 3 :(得分:2)

我将提到C++11 standard的“C.1 C ++和ISO C”。该文件对每一种差异及其对发展的影响都有所打击。

相关问题