MDK的bug还是我的bug----volatile被优化
程序没有开中断,其实MDK也不会识别你有没有开中断(其实我是在开中断的时候试出来的)下面的语句while里面翻译错了~,声明我用的是D版typedef unsigned long ulong;
volatile ulong *Pt;
int main(void)
{
volatile ulong i;
Pt = &i;
while(1)
{
*(volatile ulong *)0x50004000 = i;
}
}
void SysTick_Handler(void)
{
++*Pt;
}
上面的volatile变量翻译的不对,汇编如下:
main:
0x00000168 B508 PUSH {r3,lr}
0x0000016A 4906 LDR r1,; @0x00000184
0x0000016C 4668 MOV r0,sp
0x0000016E 6008 STR r0,
0x00000170 4905 LDR r1,; @0x00000188
0x00000172 9800 LDR r0,
0x00000174 6008 STR r0,
0x00000176 E7FD B 0x00000174 这里一直这样循环,也没有加载过程,郁闷ing,优化级别调到最低没事~
SysTick_Handler:
0x00000178 4802 LDR r0,; @0x00000184
0x0000017A 6800 LDR r0,
0x0000017C 6801 LDR r1,
0x0000017E 1C49 ADDS r1,r1,#1
0x00000180 6001 STR r1,
0x00000182 4770 BX lr
大家看看,是不是用D版都会这样?还是我的表达有问题~希望是我哪里写错了。我用的是MDK V4.03 看不出有什么问题啊,i是局部变量,本来就会放在寄存器中而不需要加载。 volatile应该不分的呀,即使是局部变量我既然声明成了volatile那么他就要去源地址去取东东呀 把 i 定义成全局变量试试?!
还有,LZ用的编译程序版本多少? 回复【3楼】linnjing
把 i 定义成全局变量试试?!
还有,lz用的编译程序版本多少?
-----------------------------------------------------------------------
全局的就变味道啦(全局可以),关键是局部的volatile就不管用了吗,郁闷ing
我的版本是
http://cache.amobbs.com/bbs_upload782111/files_28/ourdev_551291.jpg
(原文件名:未命名.jpg) en 编译器的错误。
GCC是这样的:
main:
sub sp, sp, #8
ldr r3, .L5
add r0, sp, #4
mov r2, #1342177280
str r0,
add r2, r2, #16384
.L2:
ldr r1,
str r1,
b .L2
.L6:
.align2
.L5:
.word Pt 回复【5楼】minux 啊啊?
en 编译器的错误。
gcc是这样的:
main:
sub sp, sp, #8
ldr r3, .l5
add r0, sp, #4
mov r2, #1342177280
str r0,
add r2, r2, #16384
.l2:
ldr r1,
str r1,
b .l2
.l6:
.align2
.l5:
.word pt
-----------------------------------------------------------------------
这样倒是合理
.L2:
ldr r1,
str r1,
b .L2 这个要看编译器的说明,里面一定有讲的,volatile的作用范围 试试最新版,估计应该会修正这个问题 那再这样试试,
*(volatile ulong *)0x50004000 = *Pt
其实感觉这样做比较正常
typedef unsigned long ulong;
volatile ulong i;
int main(void)
{
while(1)
{
*(volatile ulong *)0x50004000 = i;
}
}
void SysTick_Handler(void)
{
++i;
}
你这样做算什么?检测KEIL MDK?!你这就是变着法的折腾嘛!!
不如这样,把这个问题问问Keil,搞不好算你发现了一个BUG,keil回头送你一套正版的也说不定呢 回复【楼主位】david_ming
-----------------------------------------------------------------------
LZ这么写代码不是太好的习惯。有点类似于考察编译器的推断行为。
LZ的代码总的来说,都是对i的读操作,无论是i的地址还是i的数据。对这种情况,编译器可以有不同的选择:A,对volatile的变量不优化,每次操作必须造成内存访问;B,跟踪对i的各种引用关系和操作,决定何种程度的优化;C,单纯看对volatile变量自身的引用关系,决定何种优化。
Keil可能用的是C;GCC可能是A;B的消耗太高,估计不会有人用。。。
这个问题,应该说,不应该是编译器的Bug;而是采用了不够良好的描述,在编译器的优化策略下导致的问题。估计LZ用的Keil也不是Debug模式的。 【7楼】 dianzidog
volatile的语义是C标准里明确定义的。 咦?局部变量谁来改它? LZ,你是不是吃饱了? 用局部变量是因为尽量提高代码的复用性,我写的这个代码是精简化了的,我的两个程序是在不同的文件里边,Systick函数是单独的一个文件,然后include进来,上面的代码只是验证一下KEIL 尝试给一个明确写操作,避免只读优化:i = (volatile unsigned long *)(&i);在While前边,试试看吧。
尽管不清楚你为什么不在i上加个static。毕竟你的pt是全局的,要可重入也不是这样的啊。 回复【15楼】dr2001
尝试给一个明确写操作,避免只读优化:i = (volatile unsigned long *)(&i);在while前边,试试看吧。
尽管不清楚你为什么不在i上加个static。毕竟你的pt是全局的,要可重入也不是这样的啊。
-----------------------------------------------------------------------
只要是使 i 分配在全局区域的关键字都可以正确执行,问题锁定在局部变量的volatile是不是比较矛盾 回复【16楼】david_ming
-----------------------------------------------------------------------
我所说的方式,和把i放在全局区域或赋予全局的生存期,都没有关系。因为LZ位代码中,对volatile的i没有任何写操作,因而编译器完成了只读优化。那么,我们在While的前边,加入一个volatile的写操作,可能会导致编译器放弃对i的只读优化。
局部作用域,局部生存期的动态变量,volatile的,还是未见直接写入的(编译器处理的时候,看到的都是Read操作),要不要优化呢……
另外,引用一个未初始化的自动变量。。。也不是说是个编译器就能弄清楚的行为。 回楼上,用你的方法报错如下:
main.c(12): error:#513: a value of type "volatile ulong *" cannot be assigned to an entity of type "ulong" 【17楼】 dr2001
不啊,加了volatile后,编译器就不应该做那些优化了。
尤其是编译器可以推断出i的地址并非绝对不会有写入,因为已经给全局变量赋予过&i了(同时那个全局指针还是volatile ulong *类型)。
按照编译器的行为方式,只要不能确保不会在别的地方写入的volatile变量,肯定是不能做只读优化的。
总之肯定是编译器对于volatile的处理有误。 我在问问KEIL的FAE,英文不太好 看来真像是的MDK的bug,那个FAE说要去向Team反映 i不是static哦 无意中看到这帖子,这么好的主题成为烂尾楼岂不可惜了{:titter:}
RVMKD编译器是嵌入式IDE里遵守C标准的典范,所以不要轻易怀疑它的语法BUG。
第一,按照C语言规范,类型限定符(volatile 和 const)只有通过左值访问时才会起作用,而楼主程序里的变量“ i ” 始终是作为右值访问的,编译器可以对它执行优化。
第二,volatile 关键字并不是要求编译器对某个对象不要执行优化,它的确切的含义是:对某个对象的优化不能跨越序列点。如何理解这句话?虚拟世界实验室的《重入与线程安全性解惑》对此做了精确的解释。
laoshuhunya 发表于 2019-1-31 22:01
无意中看到这帖子,这么好的主题成为烂尾楼岂不可惜了
RVMKD编译器是嵌入式IDE里遵守C标准的典 ...
楼上好厉害,学习了 Arm Compiler 5.06的volatile优化bug在之前的版本中的确存在过……只不过基本上都不是中国人发现的……默默飘过。
考虑到大家生存不易,代码能运行结果对就行了,我就不强求所有人遇到问题都像邻国从业人员那样打破砂锅问到底了。
页:
[1]