1最易变的关键字 volatile 类型修饰符
用volatile修饰的变量表示可以被某些编译器未知的因素更改,比如操作系统、硬件或者其他线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。比如:volatile关键字告诉编译器某变量是随时可能发生变化的,每次使用它的时候必须从内存中取出它的值,因而编译器生成的汇编代码会重新从它的地址中读取数据。
这样如果i是一个寄存器变量或者表示一个端口数据或者是多个线程的共享数据,就容易出错,所以说volatile可以保证对特殊地址的稳定访问。
但是注意通过下面的内容,会对const和volatile有更深的理解:
#include<iostream>
using namespace std;
int main()
{
const int i=0;
int *p=const_cast<int*>(&i);
*p=2;
cout<<"i="<<i<<"\n*p="<<*p<<endl;
cout<<"&i="<<&i<<"\np="<<p<<endl;
return 0;
}
dec++和vc++运行结果都是
i=0 *p=2 且&i和p的值相等.
造成这样的原因:
1 上面的代码是强制类型转换,绕过编译器静态类型检查,从而获取变量的地址,因而在程序中只要有合法地址(非操作系统的保护内存)就可以修改地址中的数据,语言中const以及其他只是在语法上限制,无法从根本上限制。
2
但为什么在输出i的值时,仍然是0呢?
上面的代码如果修改为:
const int i=0;
int *p=(int*)&i;
*p=100;
这样i的内容也被修改了。
从而,我们想到如果使用C++中的另一个关键字:volatile,它就是用来解决这个问题。
因为从寄存器访问变量比从内存要快,所以如果一个变量在某次使用过后没有被显式修改,那么编译器将尽量从寄存器读入它的值。加volatile可以强制要求编译器每次用到这个变量时都从内存中提取它的值。所以这样就会得到正确结果:
#include<iostream>
using namespace std;
int main()
{
volatile const int i=0;
int *p=const_cast<int*>(&i);
*p=2;
cout << "i=" << i << "\n*p=" << *p << endl;
cout<<"&i="<<&i<<"\np="<<p<<endl;
return 0;
}
完全是因为前面加了const的缘故, 所以如果没有volatile, 编译器在碰到const变量的时候,用立即数代替。
volatile跟const是冲突的, 如果在const中使用volatile, 那么volatile是没作用的。
volatile的真正作用是, 在任何使用变量i的时候, 都去取地址,读地址的值,而如果不加volatile的话, 并且有优化的话,那么在连续的对i操作的情况下, 往往是放到寄存器中操作。
用volatile修饰的变量表示可以被某些编译器未知的因素更改,比如操作系统、硬件或者其他线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。比如:volatile关键字告诉编译器某变量是随时可能发生变化的,每次使用它的时候必须从内存中取出它的值,因而编译器生成的汇编代码会重新从它的地址中读取数据。
这样如果i是一个寄存器变量或者表示一个端口数据或者是多个线程的共享数据,就容易出错,所以说volatile可以保证对特殊地址的稳定访问。
但是注意通过下面的内容,会对const和volatile有更深的理解:
#include<iostream>
using namespace std;
int main()
{
const int i=0;
int *p=const_cast<int*>(&i);
*p=2;
cout<<"i="<<i<<"\n*p="<<*p<<endl;
cout<<"&i="<<&i<<"\np="<<p<<endl;
return 0;
}
dec++和vc++运行结果都是
i=0 *p=2 且&i和p的值相等.
造成这样的原因:
1 上面的代码是强制类型转换,绕过编译器静态类型检查,从而获取变量的地址,因而在程序中只要有合法地址(非操作系统的保护内存)就可以修改地址中的数据,语言中const以及其他只是在语法上限制,无法从根本上限制。
2
但为什么在输出i的值时,仍然是0呢?
上面的代码如果修改为:
const int i=0;
int *p=(int*)&i;
*p=100;
这样i的内容也被修改了。
从而,我们想到如果使用C++中的另一个关键字:volatile,它就是用来解决这个问题。
因为从寄存器访问变量比从内存要快,所以如果一个变量在某次使用过后没有被显式修改,那么编译器将尽量从寄存器读入它的值。加volatile可以强制要求编译器每次用到这个变量时都从内存中提取它的值。所以这样就会得到正确结果:
#include<iostream>
using namespace std;
int main()
{
volatile const int i=0;
int *p=const_cast<int*>(&i);
*p=2;
cout << "i=" << i << "\n*p=" << *p << endl;
cout<<"&i="<<&i<<"\np="<<p<<endl;
return 0;
}
完全是因为前面加了const的缘故, 所以如果没有volatile, 编译器在碰到const变量的时候,用立即数代替。
volatile跟const是冲突的, 如果在const中使用volatile, 那么volatile是没作用的。
volatile的真正作用是, 在任何使用变量i的时候, 都去取地址,读地址的值,而如果不加volatile的话, 并且有优化的话,那么在连续的对i操作的情况下, 往往是放到寄存器中操作。
只要是cosnt定义的变量, 并且这个变量是用立即数初始化的, 那么, 在使用这个变量的时候, 编译器一定是用立即数代替。
在笔记中综合了各种论坛等网上的内容,甚至使用的例子有的都是网上论坛中的例子,在此只是为了自己查看的时候方便和分享我在学习中的收获,无侵犯原著的意思,请见谅。