指向 struct 的指针可以为 unsigned char 数组起别名吗?
Can a pointer to struct alias an unsigned char array?
#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 中的指针别名导致的问题。我想知道上面的代码是否违反了任何规则。它会导致问题吗?
我知道位域的顺序取决于机器和实现。然而,我的问题是关于指针别名规则,我想更清楚地理解它
它确实打破了严格的别名。一些(理智的)编译器确实推断出显然 tptr
应该被允许使用别名 a
,但是标准并不能保证这一点。事实上,GCC 不会将 tptr
视为别名 a
.
另一个问题是a
的对齐。 x86 在这方面相当宽容,但许多其他架构(包括 ARM)则不然。
考虑 (int)&a == 0xFFF02
和 sizeof(int) == 4
架构支持仅从本身是 sizeof(int)
的倍数的地址获取 int
s。
这样的 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
) 并且不要通过其他方式修改位域。
如果可移植性不是问题,请确保设置适当的编译器标志以保证您期望的位域打包。
#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 中的指针别名导致的问题。我想知道上面的代码是否违反了任何规则。它会导致问题吗?
我知道位域的顺序取决于机器和实现。然而,我的问题是关于指针别名规则,我想更清楚地理解它
它确实打破了严格的别名。一些(理智的)编译器确实推断出显然 tptr
应该被允许使用别名 a
,但是标准并不能保证这一点。事实上,GCC 不会将 tptr
视为别名 a
.
另一个问题是a
的对齐。 x86 在这方面相当宽容,但许多其他架构(包括 ARM)则不然。
考虑 (int)&a == 0xFFF02
和 sizeof(int) == 4
架构支持仅从本身是 sizeof(int)
的倍数的地址获取 int
s。
这样的 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
) 并且不要通过其他方式修改位域。
如果可移植性不是问题,请确保设置适当的编译器标志以保证您期望的位域打包。