c99标准也就是C语言在99年修订的最新标准,想一下99年我还在上小学-_!,虽然只是一个c99某些新特性的笔记,尽量写清楚,做笔记的同时,也可以对大家有帮助。
个人感觉最常用的莫过于别的语言都已经有的,for循环内变量的初始化,如在c99之前ansi c标准的for循环代码都是这样来写:
1
2
3
4
5int i = 0;
for (i = 0; i < val; i++)
{
// some code
}而c99标准里可以将变量放入循环体当中,如下:
1
2
3
4for (int i = 0; i < val; i++)
{
// some code
}之所以放在第一位是感觉这个太常用了。
双斜线形式的注释,c99之前的的注释都是 / code comments /,c99标准加入了//这种c++的形式的单行注释。
变长数组,c99之前的数组长度是必须固定的,想要变长就需要使用malloc动态分配动态长度的内存,如下:
1
2
3
4
5
6int *vla = (int *)malloc(sizeof(int) * length);
for (int i = 0; i < length; i++)
{
vla[i] = i;
}
// 使用完之后free(vla)有了c99标准就可以直接在使用数组的时候,定义一个数组长度是变量的数组,如:
1
2
3
4
5for (int i = 0; i < length; i++)
{
array[i] = i;
}
// 只限于在创建时动态指定,后期不可随意变动长度这样就定义了一个长度为length的数组,length可以手动指定。但是这种变长数组的意思是指在确定数组长度的时候可以动态的(由变量来指定),并不是指在创建数组之后可以随意变动数组的长度。
指定域的初始化,也就是c99中可以对结构体或者数组进行某一部分的初始化,或者是某个成员的初始化。如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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;
}可伸缩型的数组成员,这个在gcc中早就有对应的扩展,常见的写法就是:
1
2
3
4
5struct fixible
{
int flag;
char ext[0];
};这样儿的好处就是不用指定ext的最大范围,而是根据需要,灵活指定ext所需要的长度。c99把这个功能加了进来。一个常见的例子就是统计每一行文本的长度与内容,长度未知的情况,可以这么写:
1
2
3
4
5
6
7
8
9
10
11
12
13
14struct 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
}这样针对不同长度的文本,都会分配正合适大小的结构来存储长度与内容。
bool类型,c99加入了一个stdbool头文件,里面定义了bool的false与true。这个不用多说,#include <stdbool.h>, 就可以用false与true了。不用自己再define或者enum了。
混合声明,之前的c语言都是一堆变量都在函数开头一股脑的定义好,现在有了c99标准,就可以随时定义变量并使用而不必全部写在开头了。
func内置常量,c99加入了这个常量,义指func所在行所处的函数名。这个对于调试还是相当有用的。可以直接通过调试语句配置LINE打印出log所在的函数。
上面提到了调试语句,就不得不提另一个比较好用的,变参宏,c99加入变参宏,可以让程序员很自由写一些带变参的调试宏,如:
1
2
3
4
5
6
7
8
9
10
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(); 这样来调用这个调试语句,这只是一个示例,你可以将调试语句写得更精细
复合常量,也就是在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
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;
}这样在实际项目中可能很少这样来用,但是对于测试代码应该很有帮助,不用再定义一个变量初始化好了再传入参数,直接使用复合变量直接传入就可以了,节省了一步操作。针对团队项目来说,应该是写清楚明了更有助于大家开发。
long long类型,没错,就是c99才开始支持的,scanf和printf的格式化字符串ll或者LL也是c99才开始支持的。同时引用了float,double complex复数,增加了相关复数运算,都在<complex.h>头文件中。
inline关键字,c99为c引入了内联函数,普通的宏只是单纯的字符串展开与替换,内联函数可以进行一些参数检查等相关的一些宏做不到的事。在本文件中使用刚需要声明为static inline,如果需要外部使用则需要在声明中extern inline,否则会出现编译不过的情况。