volatile关键词
volatile是一个类型修饰符(type specifier),就像我们熟悉的const一样,它是被设计用来修饰被不同线程访问和修改的变量;volatile的作用是作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值。
简单地说就是防止编译器对代码进行优化。
例如,在多线程,或者是存在中断的场景下:
buff[0]=0x01;
buff[0]=0x02;
buff[0]=0x03;
buff[0]=0x04;
编译器可能会将上面4行代码优化为1行 buff[0]=0x04;
但是,可能我们想要的结果就是需要连续运行着四段代码,因为有可能在另外的线程或中断访问buff[0]时,我们需要得到一个实时的结果,可能是0x01,也可能是0x03,但如果不加volatile关键词,可能得到的值永远都是0x04。
do{}while(0)的技巧用法
(1)在后面要加分号,使调用如同函数
在定义宏后,使用do{}while(0)如果不加分号会直接报错
(2)避免括号等使用因素对实际运行造成影响
例如,定义一个宏:
#define foo(x) bar(x); baz(x)
然后你可能这样调用:
foo(wolf);
这将被宏扩展为:
bar(wolf); baz(wolf);
这的确是我们期望的正确输出。下面看看如果我们这样调用:
if (!feral)
foo(wolf);
那么扩展后可能就不是你所期望的结果。上面语句将扩展为:
if (!feral)
bar(wolf);
baz(wolf);
显而易见,这是错误的。如果使用do while写法即可避免这个问题:
if (!feral)
do { bar(wolf); baz(wolf); } while (0);
等价于:
if (!feral) {
bar(wolf);
baz(wolf);
}
(3)避免空宏引起的warning
内核中由于不同架构的限制,很多时候会用到空宏,在编译的时候,空宏会给出warning,为了避免这样的warning,就可以使用do{}while(0)来定义空宏:
#define EMPTYMICRO do{}while(0)
(4)避免使用goto对程序流进行统一的控制
有些函数中,在函数return之前我们经常会进行一些收尾的工作,比如free掉一块函数开始malloc的内存,goto一直都是一个比较简便的方法:
int foo()
{
somestruct* ptr = malloc(。..);
dosomething.。.;
if(error)
{
goto END;
}
dosomething.。.;
if(error)
{
goto END;
}
dosomething.。.;
END:
free(ptr);
return 0;
}
由于goto不符合软件工程的结构化,而且有可能使得代码难懂,所以很多人都不倡导使用,那这个时候就可以用do{}while(0)来进行统一的管理:
int foo()
{
somestruct* ptr = malloc(。..);
do{
dosomething.。.;
if(error)
{
break;
}
dosomething.。.;
if(error)
{
break;
}
dosomething.。.;
}while(0);
free(ptr);
return 0;
}
这里将函数主体使用do()while(0)包含起来,使用break来代替goto,后续的处理工作在while之后,就能够达到同样的效果。
(5)定义一个单独的函数块来实现复杂的操作:
当你的功能很复杂,变量很多你又不愿意增加一个函数的时候,使用do{}while(0);,将你的代码写在里面,里面可以定义变量而不用考虑变量名会同函数之前或者之后的重复。