指向struct alias的指针是否可以是unsigned char数组?

时间:2016-06-18 19:51:32

标签: c pointers strict-aliasing

#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的顺序依赖于机器和实现。然而,我的问题是关于指针别名规则,我想更清楚地理解

1 个答案:

答案 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 ints 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.