有一堆不兼容性已经存在了很长时间(C90或更早),以及一堆非常好的特性在C99和C11中。这些都是我能想到的。
int *array = malloc(sizeof(*array) * n);
int *array = (int *) malloc(sizeof(*array) * n);
int *array = new int[n];
C99很好,C程序员应该普遍使用它
C99的新特性对于一般编程非常有用。虽然可变长度数组和restrict
并不是(在我看来)针对一般用途设计的,但主要是为了将FORTRAN和数值程序员引入到C语言中(尽管restrict
有助于自动向量化器)。由于任何使用restrict
的符合规范的程序仍然会以完全相同的方式工作(但可能不太快),如果在文件顶部#define restrict
,那么这并不是一个大问题。在实际开发中,可变长度数组似乎比较少见。
灵活数组成员可以很好用。请注意,这些不同于可变长度数组!人们已经使用这个技巧多年了,但官方支持意味着更少的输入,并且它还允许我们在编译时制定常量。(旧方法是创建大小为1的数组,但计算分配大小确实很麻烦。)
struct lenstr {
unsigned length;
char data[];
};
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"
};
int hex_digits[256] = { ['0'] = 0, ['1'] = 1, ['2'] = 2, ['f'] = 15 };
inline关键字的行为是不同的,您可以选择在该单元中添加外部声明以获取未声明为inline的函数的非inline版本。
复合字面量。
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运行时只提供了一个名为_snprintf
的函数,该函数不能保证将NUL终止符添加到字符串中。(snprintf
在 C++11 中出现,但仍然明显缺少 MSVC C 运行时支持)
匿名结构体和共用体 (自从很久以前就有GCC扩展,C11标准中包括它们)(匿名共用体显然在C++03中存在,但在C模式下没有MSVC支持):
struct my_value {
int type;
union {
int as_int;
double as_double;
};
};
正如您所看到的,这些特性只是为了节省许多打字(复合字面量),或使程序更易于调试(灵活的数组成员),更易于避免错误(指定初始化器/忘记初始化结构字段)。这些都不是激烈的变化。
对于语义上的区别,我确定别名规则不同,但大多数编译器现在足够宽容,我不确定您将如何构建测试用例来证明。C和C ++之间的差异是每个人都会谈到的旧sizeof('a')
表达式,在32位C系统上通常为4,但在C ++中始终为1。但是,没有人关心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前端。
<cfenv>
或来自<cmath>
的新浮点函数这样的东西。 - Christian Rau