首页 > 解决方案 > Does the following violates strict aliasing

问题描述

Consider the following code:

*((unsigned int*)((unsigned char *)0x400000));

Does it violate strict aliasing?

From the strict aliasing rule:

An object shall have its stored value accessed only by an lvalue expression that has one of the following types:

...

For a violation to occur, there must be an object of type unsigned char, so when accessed with unsigned int* a violation will occur.

Now, does (unsigned char *)0x400000 constitute an unsigned char object at address 0x400000? if not, than there is actually no object with stored value of type unsigned char here, so the access to it with a unsigned int does not violate the rule.

Note the following phrase about object:

Object

region of data storage in the execution environment, the contents of which can represent values

NOTE When referenced, an object may be interpreted as having a particular type; see 6.3.2.1.

So, since (unsigned char *)0x400000 does not constitute an unsigned char object reference (to my understanding) there is no object of type unsigned char in the presented code, so it seems that there is no violation.

Am I correct?


With respect to @Antti Haapala answer:

If we assume that integer to pointer conversion of both converting 0x400000 to unsigned char* and to unsigned int* has on my system a defined behavior with no trap representation and well aligned, and that is in order to fill the implementation-defined gap from the standard:

An integer may be converted to any pointer type. Except as previously specified, the result is implementation-defined, might not be correctly aligned, might not point to an entity of the referenced type, and might be a trap representation

Will that change the answer to my question?

标签: ccastinglanguage-lawyerstrict-aliasing

解决方案


Essentially, strict aliasing isn't applicable when dealing with hardware registers, since the committee apparently never considered hardware-related programming scenarios or memory-mapped registers.

Strict aliasing only applies in scenarios where the compiler is able to determine an effective type of what's actually stored in memory. If you take a hardware address and lvalue access it, the contents there can never have an effective type that the compiler is aware of. This means that when reading the data, I suppose this part from 6.5 would apply:

For all other accesses to an object having no declared type, the effective type of the object is simply the type of the lvalue used for the access.

In your case unsigned int. Please note that the middle cast to unsigned char* is completely superfluous both in terms of strict aliasing and in terms of lvalue access to the hardware. It should be removed.

If you do a write access however, the compiler is free to treat the value at that address as the effective type used through the write access:

If a value is stored into an object having no declared type through an lvalue having a type that is not a character type, then the type of the lvalue becomes the effective type of the object for that access and for subsequent accesses that do not modify the stored value.

Basically the rules of effective type and strict aliasing don't make sense when dealing with hardware addresses, so the compiler can't do much with them. In addition, such accesses often don't make any sense unless the pointer is volatile qualified, preventing any attempts of optimization based on strict aliasing.

Just to be sure, always compile with -fno-strict-aliasing when doing any form of embedded systems programming.


推荐阅读