2016-06-18 64 views
0
#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中的指针别名问题。我想知道上面的代码是否违反了任何规则。它会导致问题吗?可以指向结构别名unsigned char数组的指针吗?

我知道位域的顺序是依赖于机器和实现的。然而,我的问题是关于指针别名规则,我想更清楚地理解它

+0

这不是测验网站。你为什么认为它不? – Olaf

+0

'#include“stdio.h”'是不寻常的。你为什么不使用'#include '? – melpomene

+2

我不知道别名,但我很确定'tptr = ...'行有未定义的行为。首先,'B x; (A *)(void *)&x'不能保证做任何明智的事情(你只能保证能够从'void *'转换回原始类型'B *')。其次,即使它工作,结构可能有对齐要求。 – melpomene

回答

0

它确实打破了严格的别名。一些(更清晰)的编译器确实推断明显应该允许tptr别名a,但这不是标准保证的。事实上,海湾合作委员会不会考虑tptr别名a

另一个问题是对齐a。 x86在这方面相当宽容,但包括ARM在内的许多其他架构都不是。

在架构上考虑(int)&a == 0xFFF02sizeof(int) == 4,该架构仅支持从本身为sizeof(int)的倍数的地址获取int。 这样一个unaligned access会导致总线错误,如果你做*(int*)&a或更糟糕的程序访问错误的位置。

为了避免出现未定义的行为,请记住通过unsigned char*可以保证访问没有对齐或别名约束,而不是相反。因此,使用:

test buf; 
can_recv((unsigned char*)&buf, sizeof buf); 
if(tptr->a == 0xCDE) 
{ 
    printf("\n data received ok"); 

} 

另一个可移植性问题是,你期望位域以某种方式打包。 The standard doesn't guarantee that however。如果您想要便携式行为,请将自己限制在位域接口(bitfield.b1 = 1),并且不要通过其他方式修改该位。

如果可移植性不是问题,请确保设置适当的编译器标志,以保证您所期望的位域打包。

+1

我会建议所有*理智*编译器应该认识到,明确地转换指针的行为应该作为警报铃“嘿这东西将别名”,前提是所有使用类型转换指针的访问完成之前使用外型。基本原理以编译器没有理由期望别名的指针来描述规则;我没有看到这个规则曾经打算暗示编译器忽略了清晰明显的别名迹象 - 这个标准的作者可能认为这很明显,并不需要说明。 – supercat