78

C99已经存在了 10 多年,但对它的支持一直很慢,所以大多数开发人员都坚持使用 C89。即使在今天,当我在 C 代码中遇到 C99 特性时,我有时也会感到有点惊讶。

现在大多数主要编译器都支持 C99(MSVC 是一个明显的例外,一些嵌入式编译器也落后了),我觉得使用 C 的开发人员可能应该知道他们可以使用哪些 C99 特性。一些特性只是以前从未标准化过的常见特性(snprintf例如),或者在 C++ 中很熟悉(灵活的变量声明放置,或单行//注释),但一些新特性是在 C99 中首次引入的,并且是对很多程序员来说是陌生的。

您认为 C99 中最有用的新功能是什么?

作为参考,C99 标准(标记为草案,但据我所知与更新的标准相同)、新功能列表GCC C99 实施状态

请每个答案一个功能;随意留下多个答案。鼓励展示新功能的简短代码示例。

4

17 回答 17

79

我太习惯打字了

for (int i = 0; i < n; ++i) { ... }

在 C++ 中,使用非 C99 编译器很痛苦,我不得不说

int i;
for (i = 0; i < n; ++i ) { ... }
于 2010-01-12T06:29:23.030 回答
73

stdint.h, 定义int8_t,uint8_t等。不再需要对整数的宽度做出不可移植的假设。

uint32_t truth = 0xDECAFBAD;
于 2010-01-12T06:26:46.877 回答
67

我认为新的初始化机制非常重要。

struct { int x, y; } a[10] = { [3] = { .y = 12, .x = 1 } };

好的 - 不是一个令人信服的例子,但符号是准确的。您可以初始化数组的特定元素和结构的特定成员。

也许一个更好的例子是这个——尽管我承认它并不是非常引人注目:

enum { Iron = 26, Aluminium = 13, Beryllium = 4, ... };

const char *element_names[] =
{
    [Iron]      = "Iron",
    [Aluminium] = "Aluminium",
    [Beryllium] = "Beryllium",
    ...
};
于 2010-01-12T06:50:40.523 回答
52

支持以 . 开头的单行注释//

于 2010-01-12T06:19:09.933 回答
51

可变长度数组:

int x;
scanf("%d", &x);
int a[x];
for (int i = 0; i < x; ++i)
    a[i] = i * i;
for (int i = 0; i < x; ++i)
    printf("%d\n", a[i]);
于 2010-01-12T14:28:51.763 回答
41

能够在块开始以外的位置声明变量。

于 2010-01-12T09:11:37.810 回答
36

可变宏。使生成具有无限数量参数的样板代码变得更加容易。

于 2010-01-12T06:27:30.117 回答
35

snprintf() - seriously, it's worth a lot to be able to do safe formatted strings.

于 2010-01-12T17:53:37.180 回答
29

Flexible array members.

6.7.2.1 Structure and union specifiers

As a special case, the last element of a structure with more than one named member may have an incomplete array type; this is called a flexible array member. With two exceptions, the flexible array member is ignored. First, the size of the structure shall be equal to the offset of the last element of an otherwise identical structure that replaces the flexible array member with an array of unspecified length) Second, when a . (or ->) operator has a left operand that is (a pointer to) a structure with a flexible array member and the right operand names that member, it behaves as if that member were replaced with the longest array (with the same element type) that would not make the structure larger than the object being accessed; the offset of the array shall remain that of the flexible array member, even if this would differ from that of the replacement array. If this array would have no elements, it behaves as if it had one element but the behavior is undefined if any attempt is made to access that element or to generate a pointer one past it.

Example:

typedef struct {
  int len;
  char buf[];
} buffer;

int bufsize = 100;
buffer *b = malloc(sizeof(buffer) + sizeof(int[bufsize]));
于 2010-01-12T17:55:31.137 回答
29

复合字面量。逐个成员设置结构是如此 '89 ;)

您还可以使用它们来获取指向具有自动存储持续时间的对象的指针,而无需声明不必要的变量,例如

foo(&(int){ 4 });

取而代之的是

int tmp = 4;
foo(&tmp);
于 2010-01-12T08:50:46.630 回答
25

布尔类型。

您现在可以执行以下操作:

bool v = 5;

printf("v=%u\n", v);

将打印

1
于 2010-01-12T16:58:06.837 回答
19

支持inline功能。

于 2010-01-12T06:34:09.607 回答
18

复合文字,已经提到过,但这是我引人注目的例子:

struct A *a = malloc(sizeof(*a));
*a = (struct A){0};  /* full zero-initialization   */
/* or */
*a = (struct A){.bufsiz=1024, .fd=2};   /* rest are zero-initialized.  */

即使数据在堆上,它也是一种初始化数据的清晰方法。没有办法忘记对某些东西进行零初始化。

于 2011-11-04T09:21:43.810 回答
17

restrict关键字。尤其是当你处理数字时...

于 2010-09-18T22:54:28.937 回答
15

Unicode escape sequence support:

printf("It's all \u03B5\u03BB\u03BB\u03B7\u03BD\u03B9\u03BA\u03AC to me.\n");

Or even, literal Unicode characters:

printf("日本語\n");

(note: may not work depending on your locale; portable support for different encodings will take more work than this)

于 2010-01-12T17:51:05.187 回答
12

十六进制浮点常量 ( 0x1.8p0f) 和转换说明符 ( %a, %A)。如果您经常处理低级数字细节,那么这些都是对十进制文字和转换的巨大改进。

它们使您在为算法指定常量时不必担心舍入,并且对于调试低级浮点代码非常有用。

于 2010-01-12T19:39:56.970 回答
9

就个人而言,我喜欢IEC 60559:1989(微处理器系统的二进制浮点算法)的认可和更好的浮点支持。

类似地,设置和查询浮点舍入模式、检查 Nan/Infinity/subnormal numbers 等,都很棒。

于 2010-01-12T06:17:41.150 回答