有一堆不兼容问题已经存在了很长时间(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 语言中最有用的 10 个库函数。它不仅在 C++ 中缺失,而且 MSVC 运行时仅提供了一个名为 的函数_snprintf
,不能保证将 NUL 终止符添加到字符串中。(snprintf
在 C++11 中,但在 MSVC C 运行时中仍然明显不存在。)
匿名结构和联合(C11,但 GCC 永远扩展)(匿名联合显然在 C++03 中,在 C 模式下不支持 MSVC):
struct my_value {
int type;
union {
int as_int;
double as_double;
}; // no field name!
};
如您所见,其中许多功能只是为您节省大量输入(复合文字),或使程序更易于调试(灵活的数组成员),更容易避免错误(指定初始化程序/忘记初始化结构字段)。这些都不是剧烈的变化。
对于语义差异,我确信别名规则是不同的,但是现在大多数编译器都足够宽容,我不确定您将如何构建一个测试用例来演示。C 和 C++ 之间的区别是每个人都能找到的旧sizeof('a')
表达式,对于 C++,它始终为 1,但在 32 位 C 系统上通常为 4。但没人关心到底sizeof('a')
是什么。但是,C99 标准中有一些保证将现有实践编入法典。
采取以下代码。它使用一个常用技巧在 C 中定义联合类型,而不会浪费额外的存储空间。我认为这是语义上有效的 C99,我认为这在语义上是可疑的 C++,但我可能错了。
#define TAG_FUNKY_TOWN 5
struct object { int tag; };
struct funky_town { int tag; char *string; int i; };
void my_function(void)
{
struct object *p = other_function();
if (p->tag == TAG_FUNKY_TOWN) {
struct funky_town *ft = (struct funky_town *) p;
puts(ft->string);
}
}
不过,这很可惜。 MSVC 代码生成器很好,可惜没有 C99 前端。