三.volatile在程序设计中的作用
- 当读取一个变量时,为提高存取速度,编译器优化过程中有时会先把变量读取到一个寄存器内;当再取变量值时,直接从寄存器中取值;当变量值在本线程里改变时,会同时把变量的新值复制到该寄存器中,保持一致。(本线程中变量值改变,本线程中寄存器值改变)
- 编译器优化时可能出现问题,如遇到多线程编程时,变量的值可能因为别的线程而改变了,而寄存器的值不会相应改变(其他线程中变量值改变,本线程中寄存器值不改变),从而造成应用程序读取的值和实际的变量值不一致。
- volatile是一个类型修饰符,用来修饰被不同线程访问和修改的变量。被volatile类型定义的变量,系统每次使用时直接从内存中提取,不会利用cache中的原有数值,系统对volatile变量的处理不会做优化(volatile变量防止编译器优化)。
- 运用:
- 中断服务程序中修改的供其它程序检测的变量需要加volatile;
- 多线程间被多个任务共享的变量需要加volatile;
- 存储器映射的硬件寄存器(并行设备硬件寄存器)通常也要加volatile说明,因为每次对它的读写都可能有不同意义。
#include <iostream>
using namespace std;
int main(int argc,char* argv[]){
int i=10;
int a=i;
cout<<a<<endl;
// 下面汇编语句的作用就是改变内存中i的值,但是又不让编译器知道
__asm {
mov dword ptr [ebp-4], 20h
}
int b=i;
cout<<b<<endl;
getchar();
return 0;
}
//在Debug版本模式运行程序:10,32;在Release版本模式运行程序(编译器对代码进行了优化):10,10
//将语句 int i=10;改为 volatile int i=10;在Release版本模式运行程序(volatile变量不优化):10,32
四. extern的作用
对外部变量进行声明
- (一)中对全局变量介绍时提及extern关键字。编译器一般采用文件编译的方式,在编译阶段,全局变量的可见域在本文件内部。一般会出现变量未定义或重定义错误。
- extern作用:避免未定义和重定义错误,即只在一个文件中定义,其他文件不必再定义,使用即可。
//未定义错误(编译阶段)
//编译器按文件方式编译,在编译阶段,只有本文件可见,即编译A.cpp时,并不知道B.cpp中定义了i。
//链接后文件中定义的全局变量的可见性扩展到整个程序
//A.cpp
int main(int argc,char* argv[]){
cout<<i<<endl;
}
//B.cpp
int i=1;
int main(int argc,char* argv[]){
cout<<i<<endl;
}
//重定义错误(链接阶段)
//编译器按文件方式编译,在编译阶段,只有本文件可见,A不知道B定义了i,B不知道A定义了i,编译通过。
//在链接阶段,各个文件“合并”,如果有相同的变量名时,就会出现重定义错误。
//A.cpp
int i=1;
int main(int argc,char* argv[]){
cout<<i<<endl;
}
//B.cpp
int i=1;
int main(int argc,char* argv[]){
cout<<i<<endl;
}
在C++文件中调用C方式编译的变量或函数
- C++调用被C编译器编译后的变量或函数,要加extern”C”
- C++支持重载,因此C++编译后在库中的名字与C语言不同。如:声明一个函数float f(int a,char b),C++编译器会在库中将这个名字变为_f_int_char之类的东西以支持函数重载,但C语言编译器的内部名为_f。
//未定义错误:库中名字不相同
//A.cpp(C++)
extern int functionA();
extern int i;
int main(int argc,char* argv[])
{
functionA();
cout<<i<<endl;
}
//B.c(C)
int i=1;
int functionA(){}
//告诉编译器:变量i和functionA()函数是C编译器编译的
//A.cpp(C++)
extern "c"
{
int functionA();
}
extern "C"
{
int i;
}
int main(int argc,char* argv[])
{
functionA();
cout<<i<<endl;
}
//B.c(C)
int i=1;
int functionA(){}