这种未定义的行为的基本原理是什么?
警告[...]:未定义的行为:在此语句x.cpp xxx中,未定义易失性访问的顺序
为什么这条线是未定义的行为?
case 2:
Vdda = 3.3 * (*VREFINT_CAL) / ADC_DR->DATA;
声明/初始化为:
volatile short const *VREFINT_CAL = (short *) 0x1FFFF7BA;
和
volatile STRUCT_ADC_DR *ADC_DR = (STRUCT_ADC_DR*) 0x40012440;
被定义为:
typedef struct
{
unsigned DATA : 16;
unsigned : 16;
} STRUCT_ADC_DR;
是否因为编译器不确定易失性元素的访问顺序可能不同? (情况如何)
但是不应该确保计算从左到右执行,因为操作员具有相同的优先级?
volatile
意味着编译器正在读取的不是普通的内存地址,例如I / O端口。 对于两次这样的读取,您很可能会希望这些读取按特定顺序发生。
在C和C ++中,操作数的评估顺序都未定义。 如果它对你有帮助,把这个部门看作一个函数调用:
Vdda = 3.3 * divide(*VREFINT_CAL, ADC_DR->DATA);
现在的重点是,对于volatile
的订单很重要的地方,您可能不想将此决定留给编译器。 所以它警告它。
要摆脱警告,只需通过向代码添加附加顺序点来明确订购。 例如:
short const x = *VREFINT_CAL;
unsigned const y = ADC_DR->DATA;
Vdda = 3.3 * x / y;
要理解这一点,你必须知道评估顺序和优先顺序之间的区别。
拿你的表情,例如:
Vdda = 3.3 * (*VREFINT_CAL) / ADC_DR->DATA;
优先级(和括号)确定如何构建抽象语法树(AST)。 结果会是这样的:
=
Vdda
*
3.3
/
*
VREFINT_CAL
->
ADC_DR
DATA
评估顺序由序列点的存在决定。 你的代码只有一个序列点,在表达式( ;
)的末尾。
所以任何子表达式的评估顺序都是未指定的。 也就是说,编译器可以按照它认为合适的顺序进行任何中间计算和内存访问。 有些人喜欢认为子表达从左到右进行评估,但这不是语言的工作方式。
通常它不会有任何区别,但是你的两个子表达式是volatile
( *VREFINT_CAL
和ADC_DR->DATA
),所以顺序很重要。 也许这对你无关紧要,但它对编译器无疑很重要。
为了解决这个问题,使用一些临时的,只是添加一个中间序列点:
short a = *VREFINT_CAL;
unsigned b = ADC_DR->DATA;
Vdda = 3.3 * a / b;
链接地址: http://www.djcxy.com/p/73277.html