更多内容请看C/C++技术专题专题,或 volatile要害字 volatile是c/c++中一个鲜为人知的要害字,该要害字告诉编译器不要持有变量的临时拷贝,它可以适用于基础类型 如:int,char,long......也适用于C的结构和C++的类。当对结构或者类对象使用volatile修饰的时候,结构或者 类的所有成员都会被视为volatile. 使用volatile并不会否定对CRITICAL_SECTION,Mutex,Event等同步对象的需要 例如: int i; i = i + 3; 无论如何,总是会有一小段时间,i会被放在一个寄存器中,因为算术运算只能在寄存器中进行。一般来说,volatitle 要害字适用于行与行之间,而不是放在行内。 我们先来实现一个简单的函数,来观察一下由编译器产生出来的汇编代码中的不足之处,并观察volatile要害字如何修正 这个不足之处。在这个函数体内存在一个busy loop(所谓busy loop也叫做busy waits,是一种高度浪费CPU时间的循环方法) void getKey(char* pch) { while (*pch == 0) ; } 当你在VC开发环境中将最优化选项都关闭之后,编译这个程序,将获得以下结果(汇编代码)
; while (*pch == 0) $L27 ; Load the address stored in pch mov eax, DWord PTR _pch$[ebp] ; Load the character into the EAX register movsx eax, BYTE PTR [eax] ; Compare the value to zero test eax, eax ; If not zero, exit loop jne $L28 ; jmp $L27 $L28 ;} 这段没有优化的代码不断的载入适当的地址,载入地址中的内容,测试结果。效率相当的低,但是结果非常准确 现在我们再来看看将编译器的所有最优化选项开关都打开以后,重新编译程序,生成的汇编代码,和上面的代码
比较一下有什么不同
;{ ; Load the address stored in pch mov eax, DWORD PTR _pch$[esp-4]
; Load the character into the AL register movsx al, BYTE PTR [eax] ; while (*pch == 0) ; Compare the value in the AL register to zero test al, al ; If still zero, try again je SHORT $L84 ; ;}
写一次getKey函数,并把参数pch声明为volatile,代码如下: void getKey(volatile char* pch) { while (*pch == 0) ; } 这次的修改对于非最优化的版本没有任何影响,下面请看最优化后的结果: ;{ ; Load the address stored in pch mov eax, DWORD PTR _pch$[esp-4] ; while (*pch == 0) $L84: ; Directly compare the value to zero cmp BYTE PTR [eax], 0 ; If still zero, try again je SHORT $L84 ; ;} 这次的修改结果比较完美,地址不会改变,所以地址声明被移动到循环之外。地址内容是volatile,所以每次循环 之中它不断的被重新检查。 把一个const volatile变量作为参数传递给函数是合法的。如此的声明意味着函数不能改变变量的值,但是变量的 值却可以被另一个线程在任何时间改变掉。 eXPlicit要害字 我们在编写应用程序的时候explicit要害字基本上是很少使用,它的作用是"禁止单参数构造函数"被用于自动型别转换,其中比较典型的例子就是容器类型,在这种类型的构造函数中你可以将初始长度作为参数传递给构造函数.
例如: 你可以声明这样一个构造函数
class Array { public: explicit Array(int size); ...... }; 在这里explicit要害字起着至关重要的作用,假如没有这个要害字的话,这个构造函数有能力将int转换成Array.一旦这种情况发生,你可以给Array支派一个整数值而不会引起任何的问题,比如: