写在前面
一直有这样的一个概念,volatile修饰的变量,程序在读取该值的时候,不是在寄存器中读取,而是从变量所在的内存中读取。
下面写个程序测试一下
#include <stdio.h>
int b = 100;
int main(void)
{
int a = b;
int c;
a+=3;
b+=5;
c = b;
c+=7;
printf("a = %d\n",a);
printf("b = %d\n",b);
printf("c = %d\n",c);
}
gcc编译流程
1.预处理,生成预编译文件(.文件):
gcc –E hello.c –o hello.i
2.编译,生成汇编代码(.s文件):
gcc –S hello.i –o hello.s
3.汇编,生成目标文件(.o文件):
gcc –c hello.s –o hello.o
4.链接,生成可执行文件:
g cc hello.o –o hello
1,不进行优化操作
这里使用 arm-linux-gcc 编译
arm-linux-gcc -E volatile.c -o volatile.i
arm-linux-gcc -S volatile.i -o volatile.S
查看volatile.S,忽略入栈这些过程
可以看到这样一句话
ldr r3, .L3
ldr r3, [r3, #0]
这句话的目的就是从变量b的地址中取出b的值
这个过程中涉及到b变量的操作都是从变量地址中取出,未出现之前说的从寄存器中获取
2,进行优化操作
下面在编译的时候进行优化一下
arm-linux-gcc -E volatile.c -o volatile.i
arm-linux-gcc -O1 -S volatile.i -o volatile.S
优化后再看,发现出现了一开始讨论的问题,程序在读取某些变量值的时候,直接读取之前保存在寄存器中的值
3,使用volatile修饰,同时进行优化操作
使用volatile对变量进行修饰
#include <stdio.h>
volatile int b = 100;
int main(void)
{
int a = b;
int c;
a+=3;
b+=5;
c = b;
c+=7;
printf("a = %d\n",a);
printf("b = %d\n",b);
printf("c = %d\n",c);
}
编译的时候进行优化一下
arm-linux-gcc -E volatile.c -o volatile.i
arm-linux-gcc -O1 -S volatile.i -o volatile.S
这里可以看到,每次操作变量b的时候,都是
ldr r4, .L3
ldr rx, [r4, #0]
保证每次都是从变量所在的地址取值
4,结论
通过上面3个实验,可以确认volatile可以保证程序在运行过程中,对变量的取值是从变量所在的地址而不是寄存器