这种未定义的行为的基本原理是什么?

警告[...]:未定义的行为:在此语句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_CALADC_DR->DATA ),所以顺序很重要。 也许这对你无关紧要,但它对编译器无疑很重要。

为了解决这个问题,使用一些临时的,只是添加一个中间序列点:

short a = *VREFINT_CAL;
unsigned b = ADC_DR->DATA;
Vdda = 3.3 * a / b;
链接地址: http://www.djcxy.com/p/73277.html

上一篇: What is the rationale for this undefined behavior?

下一篇: Why does i = ++i invoke undefined behaviour?