C99中最有用的新function是什么?

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

现在大多数主要的编译器都支持C99(MSVC是一个明显的例外,而且一些embedded式编译器也落后了),我觉得和C一起工作的开发人员应该知道C99可用的function。 其中一些特性是从未标准化过的常用特性(例如snprintf ),或者从C ++(灵活的variables声明放置或单行//注释)中熟悉,但是一些新特性首先在C99和许多程序员都不熟悉。

你觉得C99中最有用的新function是什么?

作为参考, C99标准 (标记为草稿,但与更新的标准相同,据我所知), 新function列表和GCC C99实施状态 。

每个答案的一个function,请; 随时留下多个答案。 鼓励演示新function的简短代码示例。

我很习惯打字

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

在C ++中,我不得不说,使用非C99编译器是一件痛苦的事情

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

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

 uint32_t truth = 0xDECAFBAD; 

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

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

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

可变长度数组:

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

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

可变macros。 使用无限数量的参数生成样板代码变得更容易。

snprintf() – 严重的是,能够安全地格式化string是值得的。

灵活的arrays成员。

6.7.2.1结构和联合规范

作为特殊情况,具有多个名称成员的结构的最后一个元素可能具有不完整的数组types; 这被称为灵活的数组成员 。 除了两个例外,灵活的数组成员被忽略。 首先,结构的大小应该等于另一个相同结构的最后一个元素的偏移量,用一个未指定长度的数组代替灵活的数组成员. (或-> )运算符的左操作数是指向具有灵活数组成员的结构的指针,右操作数指定该成员,它的行为就好像该成员被replace为最长的数组(具有相同的元素types)不会使结构大于被访问的对象; arrays的偏移量应保持为灵活arrays成员的偏移量,即使这与arraysreplacearrays不同。 如果这个数组没有元素,就像它有一个元素一样,但是行为是不确定的,如果试图访问那个元素或者生成一个超过它的指针。

例:

 typedef struct { int len; char buf[]; } buffer; int bufsize = 100; buffer *b = malloc(sizeof(buffer) + sizeof(int[bufsize])); 

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

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

 foo(&(int){ 4 }); 

insteand的用法和样例:

 int tmp = 4; foo(&tmp); 

布尔types。

你现在可以做这样的事情:

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

将打印

 1 

支持inline函数。

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

 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. */ 

即使它在堆上,也是一种清楚的方式来初始化数据。 没有办法忘记零初始化的东西。

restrict关键字。 特别是当你紧缩数字…

Unicode转义序列支持:

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

甚至,字面Unicode字符:

 printf("日本語\n"); 

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

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

在为algorithm指定常量时,它们避免了四舍五入的担忧,对于debugging低级浮点代码非常有用。

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

以类似的方式,设置和查询浮点舍入模式,检查Nan / Infinity /低于正常的数字等是非常有用的。