首页 文章

C99中最有用的新功能是什么? [关闭]

提问于
浏览
75

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

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

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

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

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

17 回答

  • 10

    Unicode转义序列支持:

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

    甚至,字面上的Unicode字符:

    printf("日本語\n");
    

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

  • 16

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

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

  • 17

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

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

  • 8

    我很习惯打字

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

    在C中,使用非C99编译器是一种痛苦,我不得不说

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

    stdint.h,它定义了 int8_tuint8_t 等 . 不再需要对整数的宽度进行非可移动的假设 .

    uint32_t truth = 0xDECAFBAD;
    
  • 68

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

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

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

  • 73

    可变长度数组:

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

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

  • 65

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

  • 27

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

  • 41

    灵活的阵列成员 .

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

    例:

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

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

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

    foo(&(int){ 4 });
    

    的内心

    int tmp = 4;
    foo(&tmp);
    
  • 23

    布尔型 .

    你现在可以这样做:

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

    将打印

    1
    
  • 14

    支持 inline 功能 .

  • 32

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

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

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

  • 28

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

相关问题