(volatile int)(x)与*(volatile int *)(&x)

在stackoverflow上看到这个问题
http://stackoverflow.com/questions/22758232/why-is-access-once-so-complex 

原答主已经回答的很仔细了,不过还不够直观,这里做个试验

 1 #include <stdio.h> 
 2 #include <stdlib.h> 
 3 
 4 //加子函数防止变量优化没了 
 5 void pfunc(int a, int b) 
 6 { 
 7         int i = 0; 
 8         int sum = 0; 
 9         for (i = 0; i < b; i++) 
10         { 
11                 sum += a * i; 
12         } 
13 
14         printf("sum %x\n", sum); 
15 } 
16 
17 int main() 
18 { 
19         int i = 0x102; 
20         int a = (volatile int)i; 
21         int b = *(volatile int *)&i; 
22 
23         pfunc(a, b); 
24 } 

在arm平台上编译并截取main()的汇编
R0与R1为函数入参,从ldr指令看两者获取i的方式相同

 

 1 000083ec <main>: 
 2     83ec:        e92d4800         push        {fp, lr} 
 3     83f0:        e28db004         add        fp, sp, #4 
 4     83f4:        e24dd010         sub        sp, sp, #16 
 5     83f8:        e59f3028         ldr        r3, [pc, #40]        ; 8428 <main+0x3c> 
 6     83fc:        e50b3010         str        r3, [fp, #-16] 
 7     8400:        e51b3010         ldr        r3, [fp, #-16] 
 8     8404:        e50b3008         str        r3, [fp, #-8] 
 9     8408:        e51b3010         ldr        r3, [fp, #-16] 
10     840c:        e50b300c         str        r3, [fp, #-12] 
11     8410:        e51b000c         ldr        r0, [fp, #-12] 
12     8414:        e51b1008         ldr        r1, [fp, #-8] 
13     8418:        eb000003         bl        842c <pfunc> 
14     841c:        e1a00003         mov        r0, r3 
15     8420:        e24bd004         sub        sp, fp, #4 
16     8424:        e8bd8800         pop        {fp, pc} 
17     8428:        00000102         andeq        r0, r0, r2, lsl #2 

 

加入O1编译

 

 

 1 00008430 <main>: 
 2     8430:        e52de004         push        {lr}                ; (str lr, [sp, #-4]!) 
 3     8434:        e24dd00c         sub        sp, sp, #12 
 4     8438:        e59f0010         ldr        r0, [pc, #16]        ; 8450 <main+0x20> 
 5     843c:        e58d0004         str        r0, [sp, #4] 
 6     8440:        e59d1004         ldr        r1, [sp, #4] 
 7     8444:        ebffffe8         bl        83ec <pfunc> 
 8     8448:        e28dd00c         add        sp, sp, #12 
 9     844c:        e49df004         pop        {pc}                ; (ldr pc, [sp], #4) 
10     8450:        00000102         andeq        r0, r0, r2, lsl #2 

 

可见此时R0与R1的来源不同,R0(a)的值是将i入栈时候的值,如果此时(在ldr之后)多线程修改该值即入参就出错了(当然在这个例子中不可能,因值是全局初始化的在代码段里,但意思是这个意思),而R1仍从堆栈里取该值保证变量的正确性

结论:

1. 由此可见内核使用*(volatile typeof(x) *)(&x)的方式是必要的并且简化版((volatile typeof(x)(x))并没有起到意想中的效果(因为x是做为取出的值去做强制类型转换,而当它转换时可能已经在寄存器里了)

 

2. 理解这类问题最好方法就是写个demo直接反汇编,一切都清楚了

 

posted @ 2018-02-22 22:17  Five100Miles  阅读(1139)  评论(0编辑  收藏  举报