题目:
- 如下哪一段代码不能给地址0xaae0275c赋值为1?()
A.
volatile int *p=(int *)0xaae0275c;*p=1
B.(volatile int *)0xaae0275c[0]=1
C.volatile int *p=(int *)0xaae0275c;p[0]=1
D.*(volatile int *)0xaae0275c=1
解析
主要考察赋值到指定的内存地址
选项A,C, 通过一个指针向其指向的内存地址写入数据。
选项D,这行代码其实和上面的两行代码没有本质的区别。先将地址0xaae0275c强制转换,告诉编译器这个地址上将存储一个int类型的数据;然后通过钥匙“*”向这块内存写入一个数据。
选项B,将一个右值赋给一个左值,显然行不通。类似指针,int *p; p=1不合理
另外这里涉及到volatile关键字,顺便介绍一下 :
(1)用来同步,因为同一个东西可能在不同的存储介质中有多个副本,有些情况下会使得这些副本中的值不同,这是不允许的,所以干脆用volatile,让它只 有一个,没有其他的副本,这样就不会发生不同步的问题。
(2)防止编译器优化去掉某些语句,像我在arm中见到个寄存器非常奇怪,当中断来的时候,相对应的位置1,而清0又不能向这位写0,向这位写1才是1才 是清中断(清0),
// 假设0x560012300 为寄存器地址 #define INTPAND *(volatile unsigned int *)0x560012300
INTPAND = INTPAND; // 清中断
像编译器如果看到有INTPAND = INTPAND;这种看似无用的操作,如果没有volatile说明,编译器就很有可能会去掉INTPAND = INTPAND;实际上有用的东 西,却被编译器当没用的东西优化掉了。
(3)当地址是io端口的时候,读写这个地址是不能对它进行缓存的,这是相对于某些嵌入式中有cache才有这个。比如写这个io端口的时候,如果没有这个 volatile,很可能由于编译器的优化,会先把值先写到一个缓冲区,到一定时候 再写到io端口,这样就不能使数据及时的写到io端口,有了volatile说明以后, 就不会再经过cache,write buffer这种,而是直接写到io端口,从而避免了读写 io端口的延时。
对错误选项的分析
选项B不对的原因,还是运算符优先级的问题。
(volatile int )0xaae0275c[0]=1 的意思是,先取出0xaae0275c地址处的值,然后把该值强制转换成int类型,显然,该值是一个数值,不是变量,是右值,向该值再赋值1,就类似于 2=1; 这样的赋值,显然不对。
想改正确很容易,加上括号就OK了。
正确方式如下:
((volatile int *)0xaae0275c)[0]=1;
加上一对括号即可。