几个C语言的特性和tricky,平时不常用到,却很有用,这里记录一下。
数组传参时的static修饰,编译期检查数据长度,类似
void test_static(char param[static 5])
,意思就是传入的param的char类型数组参数至少要有五个元素。1
2
3
4
5
6
7
8
9
10
11
12// char param[static 1]检测NULL
void test_static(char param[static 5])
{
// code here
}
int main()
{
char x[3] = {1, 2};
test_static(x);
return 0;
}上述写法就会出现如下警告:
warning: array argument is too small; contains 3 elements, callee requires at least 5 [-Warray-bounds]
可参考这里。
动态指定printf输出数据的长度。可以用这种方式指定浮点数小数部分的保留位数。
1
2
3
4
5
6
7
8
9int main(int argc, char *argv[])
{
int pre = 3;
float num = 1.2432;
char *str = "test statements";
printf("num = %.*f\n", pre, num); // 输出 1.234
printf("str = %.*s\n", pre, str); // 输出 tes
return 0;
}printf还有一个格式参数%n,这个参数不输出任何内容,但是会把%n所在位置之前的字符计数都放入一个整型数值中。
1
2
3
4
5
6
7
8
9
10int main(int argc, char *argv[])
{
int pre = 4;
int out_num = 0;
char *str = "test statements";
// 回车之前的字符计数都会放在out_num中
int ret = printf("str = %.*s%n\n", pre, str, &out_num);
printf("out_num=%d, ret = %d\n", out_num, ret);
return 0;
}输出:
str = test
out_num=10, ret = 11c11添加了_Static_assert静态断言,在c11之前可以自行定义一个『静态断言』,即条件为假制造编译错误。(from stackoverflow)
1
2
3
4
5
6
7
8
9
10
int main()
{
COMPILE_TIME_ASSERT(sizeof(int)==5);
}编译提示如下:
error: ‘static_assertion_static_assertion_at_line_11’ declared as an array with a negative size
COMPILE_TIME_ASSERT(sizeof(int) == 3);
编译器的尝试性定义,代码:
1
2
3
4
5
6
7
8int i;
int i = 10; // 或者int i;
int main(int argc, char *argv[])
{
printf("%d\n", i);
return 0;
}这段代码不会报错,C标准是这样来解释的,因为声明是出现在文件域的,不是出现在某个函数域内,把其当做外部定义,同时编译器还根据定义是否有初始值来区分,带初值的就叫做定义,没有初始值的也没extern关键的字就是尝试性的定义,如果文件中同时出现了这二种(也就是一个是定义,一个是尝试性定义,像上文代码),这样那个没有带初始值的就直接当做冗余定义来处理了,不会当做redefinition,如果二个都是没带初值的,也没带extern关键字的,编译器就会把这二个尝试性定义合并成为一个初始值为0的非尝试性定义。现在上面的代码会输出10,如果把
int i = 10
改为int i;
,代码会输出0。不能在一个返回类型为void的函数中写return void,但是可以返回执行一个返回void的函数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15void foo(int x)
{
}
void bar()
{
return foo(10);
}
int main(int argc, char *argv[])
{
bar();
return 0;
}网上很多例子说三元运算符可以这样用:
1
2
3
4
5
6
7
8
9
10
int main(int argc, char *argv[])
{
int x = 10;
int y = 0;
(y < 0 ? x : y) = 20;
printf("%d %d\n", x, y);
return 0;
}也就是说三元运算符会产生一个左值,c语言里面是不可以的,这样编译:
gcc -Wall -std=c99 test.c -o test
会报编译错误,提示你表达式不能被赋值(error: expression is not assignable)。
但是在c++里的确可以。也就是上面这段代码用g++编译(会有警告)或者直接写一段c++的代码:
1
2
3
4
5
6
7
8
9
10
int main(int argc, char *argv[])
{
int x = 10;
int y = 0;
(y < 0 ? x : y) = 20;
printf("%d %d\n", x, y);
return 0;
}g++ -Wall test.cpp -o test
./test
会输出10 20。