C99标准笔记
2014年06月16日 C

c99标准也就是C语言在99年修订的最新标准,想一下99年我还在上小学-_!,虽然只是一个c99某些新特性的笔记,尽量写清楚,做笔记的同时,也可以对大家有帮助。

  1. 个人感觉最常用的莫过于别的语言都已经有的,for循环内变量的初始化,如在c99之前ansi c标准的for循环代码都是这样来写:

    1
    2
    3
    4
    5
    int i = 0;
    for (i = 0; i < val; i++)
    {
    // some code
    }

    而c99标准里可以将变量放入循环体当中,如下:

    1
    2
    3
    4
    for (int i = 0; i < val; i++)
    {
    // some code
    }

    之所以放在第一位是感觉这个太常用了。

  2. 双斜线形式的注释,c99之前的的注释都是 / code comments /,c99标准加入了//这种c++的形式的单行注释。

  3. 变长数组,c99之前的数组长度是必须固定的,想要变长就需要使用malloc动态分配动态长度的内存,如下:

    1
    2
    3
    4
    5
    6
    int *vla = (int *)malloc(sizeof(int) * length);
    for (int i = 0; i < length; i++)
    {
    vla[i] = i;
    }
    // 使用完之后free(vla)

    有了c99标准就可以直接在使用数组的时候,定义一个数组长度是变量的数组,如:

    1
    2
    3
    4
    5
    for (int i = 0; i < length; i++)
    {
    array[i] = i;
    }
    // 只限于在创建时动态指定,后期不可随意变动长度

    这样就定义了一个长度为length的数组,length可以手动指定。但是这种变长数组的意思是指在确定数组长度的时候可以动态的(由变量来指定),并不是指在创建数组之后可以随意变动数组的长度。

  4. 指定域的初始化,也就是c99中可以对结构体或者数组进行某一部分的初始化,或者是某个成员的初始化。如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    #include <stdio.h>

    struct Test
    {
    int fir;
    long sec;
    struct Test *m_ptr;
    };

    int main(int argc, char *argv[])
    {
    //只针对数组中的0,5,8三个下标位置进行初始化,其他都为0
    int array[10] = {[0] = 1, [5] = 10, [8] = 12};
    for (int i = 0; i < 10; i++)
    {
    printf("array[%d] == %d\n", i, array[i]);
    }
    //只针对后二个成员进行初始化,第一个默认初始化为0
    struct Test t = {.sec = 100L, .m_ptr = NULL};
    printf("%d\n", t.fir);
    return 0;
    }
  5. 可伸缩型的数组成员,这个在gcc中早就有对应的扩展,常见的写法就是:

    1
    2
    3
    4
    5
    struct fixible
    {
    int flag;
    char ext[0];
    };

    这样儿的好处就是不用指定ext的最大范围,而是根据需要,灵活指定ext所需要的长度。c99把这个功能加了进来。一个常见的例子就是统计每一行文本的长度与内容,长度未知的情况,可以这么写:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    struct lines_counter
    {
    int line_length;
    char content[];//必须放在成员最后
    };

    void save_content(int line_len)
    {
    struct lines_counter *lc = (struct lines_counter *)
    malloc(sizeof(struct lines_counter) + line_len + 1);
    //do something
    lc->line_length = line_len;
    //XXX
    }

    这样针对不同长度的文本,都会分配正合适大小的结构来存储长度与内容。

  6. bool类型,c99加入了一个stdbool头文件,里面定义了bool的false与true。这个不用多说,#include <stdbool.h>, 就可以用false与true了。不用自己再define或者enum了。

  7. 混合声明,之前的c语言都是一堆变量都在函数开头一股脑的定义好,现在有了c99标准,就可以随时定义变量并使用而不必全部写在开头了。

  8. func内置常量,c99加入了这个常量,义指func所在行所处的函数名。这个对于调试还是相当有用的。可以直接通过调试语句配置LINE打印出log所在的函数。

  9. 上面提到了调试语句,就不得不提另一个比较好用的,变参宏,c99加入变参宏,可以让程序员很自由写一些带变参的调试宏,如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #include <stdio.h>

    #define DEBUG(format,...) \
    printf("[Debug]: " format " -- %s -- %d \n",##__VA_ARGS__,__func__,__LINE__)

    int main(int argc, char *argv[])
    {
    DEBUG("%d == %s", 10, "debug print");
    return 0;
    }

    当然变参部分也可以为空串,为空串那么##VA_ARGS就会直接展开成空的字符串,也就是完全可以DEBUG(); 这样来调用这个调试语句,这只是一个示例,你可以将调试语句写得更精细

  10. 复合常量,也就是在c99标准里的c可以定义一个匿名的结构体或者数组,常用的地方应该就是构造一个临时变量,传给函数做参数。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    #include <stdio.h>

    struct Point
    {
    int x, y;
    };

    struct Rect
    {
    struct Point *point;
    int wid;
    int len;
    };

    void test_func(int *array, int size)
    {
    for (int i = 0; i < size; i++)
    {
    printf("%d\n", array[i]);
    }
    }
    void test_func2(struct Rect *rect)
    {
    printf("point {%d, %d} %d -- %d\n",rect->point->x, rect->point->y, rect->wid, rect->len);
    }

    int main(int argc, char *argv[])
    {
    test_func((int []){1, 2, 3, 5}, 4);
    test_func2(&(struct Rect){.point = &(struct Point){.x = 10, .y = 10}, .wid = 50, .len = 70});
    return 0;
    }

    这样在实际项目中可能很少这样来用,但是对于测试代码应该很有帮助,不用再定义一个变量初始化好了再传入参数,直接使用复合变量直接传入就可以了,节省了一步操作。针对团队项目来说,应该是写清楚明了更有助于大家开发。

  11. long long类型,没错,就是c99才开始支持的,scanf和printf的格式化字符串ll或者LL也是c99才开始支持的。同时引用了float,double complex复数,增加了相关复数运算,都在<complex.h>头文件中。

  12. inline关键字,c99为c引入了内联函数,普通的宏只是单纯的字符串展开与替换,内联函数可以进行一些参数检查等相关的一些宏做不到的事。在本文件中使用刚需要声明为static inline,如果需要外部使用则需要在声明中extern inline,否则会出现编译不过的情况。