#include "stdio.h"
/* array to store data receeived from CAN Bus */
unsigned char a[8] = {0xCD, 0xEF, 0x12, 0x34, 0x50, 0x00, 0x00, 0x00};
typedef struct {
unsigned int a:12;
unsigned int b:12;
unsigned int c:12;
unsigned int unused:28;
}test;
test *tptr;
int main(void)
{
tptr = (test*)( (void*)&a); // is this line braking any aliasing rule
if(tptr->a == 0xCDE)
{
printf("\n data received ok");
}
return 0;
}
我最近了解了由于C中的指针别名导致的问题。我想知道上面的代码是否违反任何规则。它会导致问题吗?
我知道bitfield的顺序依赖于机器和实现。然而,我的问题是关于指针别名规则,我想更清楚地理解
答案 0 :(得分:0)
It does break strict aliasing. Some (saner) compilers do deduce that obviously tptr
should be allowed to alias a
, but this is not guaranteed by the standard. In fact, GCC will not consider tptr
to be aliasing a
.
Another problem is the alignment of a
. The x86 is quite tolerant in that regard, but many other architectures, including the ARM, are not.
Consider (int)&a == 0xFFF02
and sizeof(int) == 4
on architecture that support fetching int
s only from addresses that are themselves multiples of sizeof(int)
.
Such an unaligned access would result in a bus error, if you do *(int*)&a
or even worse the program accessing the wrong location.
To stay clear of undefined behavior, remember that it is guaranteed that accesses through unsigned char*
are possible without alignment or aliasing constraints, not the other way round. Thus use:
test buf;
can_recv((unsigned char*)&buf, sizeof buf);
if(tptr->a == 0xCDE)
{
printf("\n data received ok");
}
Another portability problem, is that you expect that bitfield to be packed a certain way. The standard doesn't guarantee that however. If you want portable behavior, restrict yourself to the bitfield interface (bitfield.b1 = 1
) and don't modify the bitfied by other means.
If portability isn't a concern, make sure to set the appropriate compiler flags that guarantee the bitfield packing you're expecting.