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

Bri*_*ell 78 c c99

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

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

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

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

请回答一个问题; 随时留下多个答案.鼓励展示新功能的简短代码示例.

Jon*_*eid 77

我很习惯打字

for (int i = 0; i < n; ++i) { ... }
Run Code Online (Sandbox Code Playgroud)

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

int i;
for (i = 0; i < n; ++i ) { ... }
Run Code Online (Sandbox Code Playgroud)

  • 此外,它缩小了int变量的范围,这总是一件好事^^ (44认同)
  • @Oliver <sarcasm>然后删除指令`sub esp,4`和`add esp,4`!</ sarcasm> (2认同)

Bri*_*ell 72

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

uint32_t truth = 0xDECAFBAD;
Run Code Online (Sandbox Code Playgroud)

  • 自DE:AD:BE:EF:CA:FE以来的最佳十六进制短语. (19认同)
  • @Pacerier它只是一个用于说明这个例子的任意十六进制常量.但对于幽默价值而言,它意味着"脱咖啡因不好",暗示脱咖啡因咖啡不如真品. (5认同)
  • 好吧,我无法与他们的幽默联系起来...... (5认同)

Jon*_*ler 66

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

struct { int x, y; } a[10] = { [3] = { .y = 12, .x = 1 } };
Run Code Online (Sandbox Code Playgroud)

好的 - 不是一个引人注目的例子,但符号是准确的.您可以初始化数组的特定元素以及结构的特定成员.

也许更好的例子就是这个 - 虽然我承认它并不是非常引人注目:

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

const char *element_names[] =
{
    [Iron]      = "Iron",
    [Aluminium] = "Aluminium",
    [Beryllium] = "Beryllium",
    ...
};
Run Code Online (Sandbox Code Playgroud)

  • 这是一个引人注目的示范.有大量的枚举表和相应的字符串表. (6认同)
  • @ColeJohnson:如果你仔细看第二个例子,你会发现初始化器没有按顺序列出 - 但是可以正常工作.这不能简单地使用定义来完成.第一个示例仅初始化数组的索引4; 这也不能简单地使用定义来完成. (5认同)
  • 还应注意的是,多次使用同一索引将覆盖第二种用法,第一次使用-请在此处查看我的问题,例如:http://stackoverflow.com/questions/16742467/c99-designated-initializer-duplicate-索引未标记在所有生成的输出中或 (2认同)

gam*_*ver 51

支持以#开头的单行评论//.

  • +1我知道的所有编译器都支持这个.这是标准中提到的时间. (7认同)

Meh*_*ari 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]);
Run Code Online (Sandbox Code Playgroud)

  • 你真的认为VLA阵列很棒吗?C11使它们成为可选的. (3认同)
  • 只是不要忘记应用输入卫生措施以防止堆栈溢出(如果x为负,则防止堆栈损坏):`if(x &lt;0)x = 0; 否则(x&gt; 1024)x = 1024;` (3认同)

mik*_*csh 41

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

  • @supercat你更喜欢`int a; int b; a = f(); b = g();`到`int a = f(); int b = g();`?声明一个接近初始化位置的变量对于减少错误来说是巨大的. (5认同)
  • 我不是那么热衷于此.在我看来,变量不仅应该在需要时进入范围,而是在不需要时从范围中删除.中间区块的变量几乎总是在范围内比它们应该的时间更长. (2认同)

ken*_*ytm 36

变体宏.使用无限数量的参数生成样板代码更容易.


Dav*_*ley 34

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


Chr*_*oph 29

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

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

foo(&(int){ 4 });
Run Code Online (Sandbox Code Playgroud)

的内心

int tmp = 4;
foo(&tmp);
Run Code Online (Sandbox Code Playgroud)

  • 不是4?:((((((( (13认同)

Gre*_*osz 29

灵活的阵列成员.

6.7.2.1结构和联合规范

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

例:

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

int bufsize = 100;
buffer *b = malloc(sizeof(buffer) + sizeof(int[bufsize]));
Run Code Online (Sandbox Code Playgroud)

  • +1,最终制作出该犹太洁食。我见过的每个TCP / IP套接字代码中都有它。 (2认同)

Pat*_*ter 25

布尔型.

你现在可以这样做:

bool v = 5;

printf("v=%u\n", v);
Run Code Online (Sandbox Code Playgroud)

将打印

1
Run Code Online (Sandbox Code Playgroud)

  • 不是'v = 1`?魔法! (3认同)
  • 凡想到这一点的人都是纯洁的 (2认同)

Cod*_*ain 18

支持inline功能.

  • daf:`inline`仍然有用,因为它允许你在多个翻译单元中定义函数 - 所以你可以将它放在一个头文件中,这样就可以提供跨模块的内联机会. (7认同)

u0b*_*6ae 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.  */
Run Code Online (Sandbox Code Playgroud)

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


Ale*_* C. 17

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


Bri*_*ell 15

Unicode转义序列支持:

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

甚至,字面上的Unicode字符:

printf("???\n");
Run Code Online (Sandbox Code Playgroud)

(注意:可能不起作用,具体取决于您的语言环境;对不同编码的便携式支持将需要更多工作)


Ste*_*non 12

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

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

  • 是的,我前几天刚试图向某人解释浮点数在另一个Stack Overflow问题中是如何工作的. (3认同)

Alo*_*hal 9

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

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