I have a code snippet as given below
static unsigned int ticks; void IRQ_SomeTimer(void) { ticks ++; } int main() { int sav_ticks; sav_ticks = ticks; while (sav_ticks + TIME_TO_WAIT > *(volatile unsigned int *)&ticks); /* Do somethine here */ return 0; }
This compiles and runs on ARM-Mx targets up to optimization level O2, at optimization level O3 the code generated for
while (sav_ticks + TIME_TO_WAIT > *(volatile unsigned int *)&ticks);
is the same as the code generated for
while (sav_ticks + TIME_TO_WAIT > ticks);
Hence the code generated by O3 never comes out of the while loop!! Is this a BUG in Keil armcc(?) I am using Keil U-Vision (MDK ARM 4.73).
Well the funny thing is the code below shows error in Keil
uint8_t x; *(const uint8_t *)&x = 0x48;
It says the resulting expression from the Left hand side of the = operator is a non modifiable 'lvalue'. If cast to the qualified type has the same effect as cast to the unqualified type then the above should be perfectly valid!!
Oops I spoke too soon! After a little bit of analysis I think Footnote [44] of the standard (in draft foot note [86]) does not settle it after all!!
So the note says "A cast does not yield an lvalue. Thus, a cast to a qualified type has the same effect as a cast to the unqualified version of the type." Let us look at what this says
int x; long int y; y = (long) x; y = (volatile long) x;
In the above code the type is "long" and the cast converts it to "volatile qualified long", hence the standard says the compiler to consider the cast to "volatile long" as the same as cast to "long".
Well if we consider a type "int *" the volatile qualified type of "int *" is "int * volatile" and not "volatile int *" [this is totally a different type]. So according to the standards the compiler is free consider cast to "int *" and a cast to "int * volatile" as the same, but it is supposed to do the conversion according to standard given at 6.5.4 Cast operators paragraph 3
Conversions that involve pointers, other than where permitted by the constraints of 6.5.16.1, shall be specified by means of an explicit cast.
In my original example I do a conversion of "uint32_t *" to "volatile uint32_t *" which is not permitted by the constraint specified in 6.5.16.1 [it permits conversion of "volatile uint32_t *" to "uint32_t *" but not vice-versa]. Hence the compiler should consider my explicit cast. It is indeed a bug in armcc.
To shed more light on this as I mentioned before
the above code shown error [perfectly good] as the compiler did the conversion of type-x to type-y [Where type-x is "uint8_t *" and type-y is "const uint8_t *" and type-y is not a qualified type of type-x]
Now considering the code below
uint8_t x; *(uint8_t * const)&x = 0x48;
compiles with a simple warning as given below
main.c(15): warning: #191-D: type qualifier is meaningless on cast type
Which is apt according to the section of standards mentioned by "Andrew Neil"
P.S: Please don't ask me why I am using const and not volatile.