在阅读本文以前,请先阅读gcc的相关文档,确保对如何在c中使用汇编语言有个基本的认识。html
文档地址为:sass
https://gcc.gnu.org/onlinedoc...微信
下面用示例讲解下相关概念:函数
#include <assert.h> #include <stdint.h> #include <stdio.h> void do_check(uint32_t dwSomeValue) { uint32_t dwRes; asm("bsfl %1,%0" : "=r"(dwRes) : "r"(dwSomeValue) : "cc"); assert(dwRes == 3); } int main(int argc, char *argv[]) { do_check(8); }
编译后再以汇编形式查看do_check方法:性能
$ gcc -O3 main.c && objdump --disassemble=do_check a.out 0000000000001190 <do_check>: 1190: 0f bc ff bsf %edi,%edi 1193: 83 ff 03 cmp $0x3,%edi 1196: 75 01 jne 1199 <do_check+0x9> 1198: c3 retq 1199: 50 push %rax 119a: e8 c1 ff ff ff callq 1160 <do_check.part.0>
因为assert宏中使用了asm语句中的输出参数dwRes,因此即便asm语句没有指定volatile,do_check方法也是在正常执行的。优化
下面看下把assert方法去掉以后的do_check汇编代码:ui
$ gcc -O3 -D NDEBUG main.c && objdump --disassemble=do_check a.out 0000000000001130 <do_check>: 1130: c3 retq
由上可见,由于咱们在执行gcc时加了-D NDEBUG参数,定义了NDEBUG宏,因此上面的assert宏最终会变为空指令。spa
也就是说,do_check方法中没有任何地方在使用asm语句中的输出参数dwRes,因此gcc就会在优化后的代码中删除掉该asm语句,因此上面的do_check方法最终变成了空方法。code
那咱们将上面的asm语句加上volatile再试下:htm
void do_check(uint32_t dwSomeValue) { uint32_t dwRes; asm volatile("bsfl %1,%0" : "=r"(dwRes) : "r"(dwSomeValue) : "cc"); assert(dwRes == 3); }
编译后再以汇编形式查看do_check方法:
$ gcc -O3 -D NDEBUG main.c && objdump --disassemble=do_check a.out 0000000000001130 <do_check>: 1130: 0f bc ff bsf %edi,%edi 1133: c3 retq
由上能够看到,此次即便指定了-D NDEBUG参数,使assert宏变成了空操做,致使do_check方法中没有任何地方使用dwRes变量,但因为volatile的存在,该asm语句仍是没有被优化掉。
经过上面的例子,咱们就能够看到 volatile 是如何防止 gcc 优化代码的,可是在上面的例子中,该优化是一个正确的优化,因此不该该加 volatile。
若是有其余的asm语句,虽然它的输出参数没有被使用,但也不该该被优化掉,这个时候就应该使用 volatile 了。
但愿对你有所帮助。
完。
更多原创文章,请关注我微信公众号: