Casting pointers on embedded devices

2019-06-17 03:07发布

I encountered a strange problem when casting and modifying pointers on a 32bit embedded system (redbee econotag running contiki OS to be specific).

uint32_t array[2];
array[0] = 0x76543210;
array[1] = 0xfedcba98;

uint8_t* point = ((uint8_t*)array)+1;

printf("%08x \n", *(uint32_t*)point );

output on my computer:

98765432

output on embedded device:

10765432

My computer behaves as I expect it to, the embedded device however seems to wrap around when it reaches the end of the word. Why does this happen?

5条回答
我只想做你的唯一
2楼-- · 2019-06-17 03:11
printf("%08x \n", *(uint32_t*)point );

The * expression in this statement invokes undefined behavior: it violates aliasing rules and may do unaligned access.

查看更多
成全新的幸福
3楼-- · 2019-06-17 03:21

Because of the +1 you do an unaligned access of a 32-bit value, i.e. the address is not a multiple of four.

x86 works independently of alignment, because its roots go all the way back to 8-bit machines (maybe performance is slightly worse).

ARM requires alignment (as do many other processors), so 32-bit values should be placed at addresses that are a multiple of four bytes. Various bad things may happen if this isn't the case (wrong values, faults). For the array the compiler takes care of that, but when you explicitly cast the pointer you force it to violate alignment.

查看更多
狗以群分
4楼-- · 2019-06-17 03:24

With this code, you break the strict aliasing rule: the object pointed by point is accessed by an lvalue expression that has uint32_ttype.

C11 (n1570), § 6.5 Expressions
An object shall have its stored value accessed only by an lvalue expression that has one of the following types:
— a type compatible with the effective type of the object,
— a qualified version of a type compatible with the effective type of the object,
— a type that is the signed or unsigned type corresponding to the effective type of the object,
— a type that is the signed or unsigned type corresponding to a qualified version of the effective type of the object,
— an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union), or
— a character type.

This leads to an undefined behavior, so anything can happen.

C11 (n1570), § 4. Conformance
If a ‘‘shall’’ or ‘‘shall not’’ requirement that appears outside of a constraint or runtimeconstraint is violated, the behavior is undefined.

查看更多
我命由我不由天
5楼-- · 2019-06-17 03:34

Your target "redbee econotag" is stated as an ARM7 which has ARMv4 architecture. ARMv4 doesn't provide unaligned memory access like an ARMv7 or an intel machine.

Quoting from ARM's documentation:

On ARMv4 and ARMv5 architectures, and on the ARMv6 architecture depending on how it is configured, care needs to be taken when accessing unaligned data in memory, lest unexpected results are returned. For example, when a conventional pointer is used to read a word in C or C++ source code, the ARM compiler generates assembly language code that reads the word using an LDR instruction. This works as expected when the address is a multiple of four, for example if it lies on a word boundary. However, if the address is not a multiple of four, the LDR returns a rotated result rather than performing a true unaligned word load. Generally, this rotation is not what the programmer expects.

查看更多
走好不送
6楼-- · 2019-06-17 03:36

EDIT: please note that the body of this answer is made irrelevant by the comments it prompted

The theory of the other answers is fine, but probably doesn't help you. The actual problem is that you wrote:

uint8_t* point = ((uint8_t*)array)+1;

When you should have written something such as

uint8_t* point = (uint8_t*)(array+1);

because you need to increment the pointer as a pointer to an appropriate type (so that the increment operation will add the size of an element), before you cast it to something else.

But one might ask if you really intend to have a byte pointer to a 32-bit value. Perhaps you do intend to access it in bytewise fashion (beware that the byte ordering will vary between systems!). Or perhaps you really intended for point to be a pointer to a 32-bit value which is in turn a pointer to an 8-bit value somewhere else...

查看更多
登录 后发表回答