看一个简单的c程序,p是没加关键字volatile的int型指针,r是加关键字volatile的int型指针。
//main.c
#include <stdio.h>
void main(void)
{
int n;
int *p;
volatile int *r; //注意,这里加了volatile关键字
n=10;
*p;
n=20;
*r;
n=30;
}
看看汇编过程(arm-linux-gcc -S main.c -o main.s ):
//main.s
.arch armv4t
.fpu softvfp
.eabi_attribute 20, 1
.eabi_attribute 21, 1
.eabi_attribute 23, 3
.eabi_attribute 24, 1
.eabi_attribute 25, 1
.eabi_attribute 26, 2
.eabi_attribute 30, 6
.eabi_attribute 18, 4
.file "main.c"
.text
.align 2
.global main
.type main, %function
main:
@ Function supports interworking.
@ args = 0, pretend = 0, frame = 16
@ frame_needed = 1, uses_anonymous_args = 0
@ link register save eliminated.
str fp, [sp, #-4]!
add fp, sp, #0
sub sp, sp, #20
mov r3, #10
str r3, [fp, #-16] #[fp, #-16]即代表c代码中的变量n;
mov r3, #20
str r3, [fp, #-16] #注意,观察前2行,这里没有对“没加关键字volatile的指针p”的任何操作;
ldr r3, [fp, #-8] #[fp, #-8]即指的是指针r的值;
ldr r3, [r3, #0] #这里将指针所指的内存读到了r3,即“r3 = *r”;
mov r3, #30 #注意,观察前2行,这里对加关键字volatile的指针r”的有读操作;
str r3, [fp, #-16]
add sp, fp, #0
ldmfd sp!, {fp}
bx lr
.size main, .-main
.ident "GCC: (ctng-1.6.1) 4.4.3"
.section .note.GNU-stack,"",%progbits
从这里,可以看出,有加关键字和没加关键字volatile的区别。例如在读取状态标志位(读取后状态标志位自动“清除”),以上的两个指针操作就会有不同。
volatile 告诉编译器*r是随时可能发生变化的,每次使用它的时候必须从*r的地址中读取,因而编译器生成的可执行码会重新从*r的地址读取数据。有无volatile对IO口操作,共享内存操作等也是有影响的。这里不多说了。