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

时间:2010-01-12 06:12:44

标签: c c99

C99已存在超过10年,但对它的支持一直缓慢,因此大多数开发人员都坚持使用C89。即使在今天,当我遇到C代码中的C99功能时,我有时会感到轻微的惊讶。

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

您在C99中找到了哪些最有用的新功能?

供参考,the C99 standard(标记为草稿,但据我所知,与更新的标准相同),list of new featuresGCC C99 implementation status

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

17 个答案:

答案 0 :(得分:74)

我已经习惯了打字

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

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

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

答案 1 :(得分:71)

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

uint32_t truth = 0xDECAFBAD;

答案 2 :(得分:66)

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

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",
    ...
};

答案 3 :(得分:50)

支持以//开头的单行评论。

答案 4 :(得分:50)

可变长度数组:

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]);

答案 5 :(得分:41)

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

答案 6 :(得分:35)

Variadic宏。使用无限数量的参数生成样板代码更容易。

答案 7 :(得分:33)

snprintf() - 说真的,能够做出安全的格式化字符串是值得的。

答案 8 :(得分:28)

复合文字。逐个成员设置结构是'89;)

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

foo(&(int){ 4 });

的内心
int tmp = 4;
foo(&tmp);

答案 9 :(得分:28)

灵活的阵列成员。

  

6.7.2.1结构和联合规范

     

作为一种特殊情况,具有多个命名成员的结构的最后一个元素可以   有一个不完整的数组类型;这称为灵活数组成员。除了两个例外,忽略了灵活的数组成员。首先,结构的大小应为   等于另一个相同结构的最后一个元素的偏移量,该结构用一个未指定长度的数组替换灵活数组成员。第二,当 . (或 {{1运算符有一个左操作数,它是一个带有灵活数组成员的结构(指向),右操作数命名该成员,它的行为好像该成员被最长的数组替换(具有相同的数组)元素类型)不会使结构大于被访问的对象;数组的偏移量应保持灵活数组成员的偏移量,即使这与替换数组的偏移量不同。如果此数组没有元素,则其行为就好像它有一个元素但如果尝试访问该元素或生成一个指针,则行为未定义   它

示例:

->

答案 10 :(得分:24)

布尔型。

你现在可以这样做:

bool v = 5;

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

将打印

1

答案 11 :(得分:18)

支持inline个功能。

答案 12 :(得分: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.  */

这是一种清晰的方法来初始化数据,即使它在堆上。没有办法忘记零初始化。

答案 13 :(得分:16)

restrict关键字。特别是当你处理数字时......

答案 14 :(得分:14)

Unicode转义序列支持:

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

甚至是文字Unicode字符:

printf("日本語\n");

(注意:根据您的语言环境可能无效;对不同编码的便携式支持将需要更多工作)

答案 15 :(得分:11)

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

它们可以避免在为算法指定常量时对舍入的担忧,并且对于调试低级浮点代码非常有用。

答案 16 :(得分:8)

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

类似地,设置和查询浮点舍入模式,检查Nan / Infinity /次正规数等是很好的。