What is the rationale for this undefined behavior?

Warning[...]: undefined behavior: the order of volatile accesses is undefined in this statement x.cpp xxx

Why this line is undefined behavior?

  case 2:
    Vdda = 3.3 * (*VREFINT_CAL) / ADC_DR->DATA;

Where the declarations/initializations are:

volatile short const *VREFINT_CAL = (short *) 0x1FFFF7BA;

and

volatile STRUCT_ADC_DR *ADC_DR = (STRUCT_ADC_DR*) 0x40012440;

defined by:

typedef struct
{
  unsigned DATA         : 16;
  unsigned              : 16;
} STRUCT_ADC_DR;

Is it because the compiler isn't sure about the volatile elements could act diferent in the order they get accessed? (What is the case)

But shouldn't it be ensured that the calculation gets performed from left to right as the operators have the same priority?


volatile implies to the compiler that you are reading something that is not an ordinary memory address, like an I/O port. For two such reads, it is very likely that you will want those reads to happen in a certain order.

In both C and C++, the evaluation order of operands is not defined. If it helps you, think of the division as a function call:

Vdda = 3.3 * divide(*VREFINT_CAL, ADC_DR->DATA);

The point is now, that for volatile , where it's likely that the order is important, you might not want to leave this decision to the compiler. So it warns about it.

To get rid of the warning, simply make the order explicit by introducing additional sequence points to your code. For instance:

short const x = *VREFINT_CAL;
unsigned const y = ADC_DR->DATA;
Vdda = 3.3 * x / y;

To understand this you have to know the difference between order of evaluation and precedence.

Take your expression, for example:

Vdda = 3.3 * (*VREFINT_CAL) / ADC_DR->DATA;

Precedence (and parentheses) determines how the abstract syntax tree (AST) is built. The result would be something like this:

=
  Vdda
  *
    3.3
    /
      *
        VREFINT_CAL
      ->
        ADC_DR
        DATA

The order of evaluation is determined by the existence of sequence points. And your code has only one sequence point, at the end of the expression ( ; ).

So the order of evaluation of any subexpression is unspecified. That is, the compiler can make any intermediate calculation and memory access in any order it sees fit. Some people like to think that subexpressions are evaluated from left to right, but that's not how the language works.

Normally it will not make any difference, but two of your subexpressions are volatile ( *VREFINT_CAL and ADC_DR->DATA ) so the order matters. Maybe it does not matter to you, but it certainly matters to the compiler.

To solve the issue use some temporary, just to add a intermediate sequence point:

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

上一篇: 为什么最小的int,-2147483648,类型是'long'?

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