What is the meaning of this undefined behavior?

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

Why does this line have undefined behavior?

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

If declarations / initialization:

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

and

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

defined as follows:

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

Is it because the compiler is not sure that volatiles can act differently in the order in which they are accessed? (What's the matter)

But shouldn't the calculations be ensured from left to right, since the operators have the same priority?

+5
source share
2 answers

volatile implies that you are reading something that is not a regular memory address, such as an I / O port. For two such readings, it is very likely that you want these readings to be performed in a specific order.

In C and C ++, the order in which operands are evaluated is not defined. If this helps you, think of division as a function call:

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

Now the thing is that for volatile , where the likelihood that order is important may not want to leave this solution to the compiler. Therefore, he warns about it.

To get rid of the warning, just make the order explicit by entering additional sequence codes into your code. For instance:

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

To understand this, you need to know the difference between the order of evaluation and priority.

Take your expression, for example:

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

Priority (and parentheses) determines how the abstract syntax tree (AST) is created. The result will be something like this:

 = Vdda * 3.3 / * VREFINT_CAL -> ADC_DR DATA 

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

Thus, the evaluation procedure for any subexpression is not specified. That is, the compiler can perform any intermediate calculations and memory access in any order that it considers necessary. Some people like to think that subexpressions are evaluated from left to right, but that’s not how the language works.

This usually doesn't matter, but two of your subexpressions are volatile ( *VREFINT_CAL and ADC_DR->DATA ), so the order matters. It may not matter to you, but it certainly does matter to the compiler.

To solve the problem, use temporary ones, just to add an intermediate point in the sequence:

 short a = *VREFINT_CAL; unsigned b = ADC_DR->DATA; Vdda = 3.3 * a / b; 
+4
source

All Articles