C 是否所有成员都需要对齐指向联合的指针
给定 有一个功能是合法的吗C 是否所有成员都需要对齐指向联合的指针,c,alignment,unions,C,Alignment,Unions,给定 有一个功能是合法的吗 typedef union { unsigned char b; long l; } BYTE_OR_LONG; 叫它 unsigned long get_byte_or_long(BYTE_OR_LONG *it) { if (it->b) return it->b; else return decode_long(it->l); // Platform-dependent method
typedef union { unsigned char b; long l; } BYTE_OR_LONG;
叫它
unsigned long get_byte_or_long(BYTE_OR_LONG *it)
{
if (it->b)
return it->b;
else
return decode_long(it->l); // Platform-dependent method
// Could return (it), (it>>8), etc.
}
void测试()
{
long l=encode_long(12345678);//依赖于平台;可能返回
//(it)
这是否意味着保证指向联合类型的指针必须能够识别其中包含的任何类型的任何实例所需的实现
长问题,短回答:是的
(稍后我会找出标准参考)
基本上,这是因为结构/联合的第一个元素保证在它之前没有填充
指向对象类型的指针可以转换为指向其他对象类型的指针。如果生成的指针未正确对齐引用类型[…],则行为未定义。[C11(n1570)6.3.2.3 p7]
我找不到任何关于联合的对齐要求的明确保证,因此对联合指针的转换似乎不严格符合要求。在我的机器上,\u Alignof(char)
是1,但\u Alignof(BYTE\u或长)
是4
这是否意味着保证指向联合类型的指针必须能够识别其中包含的任何类型的任何实例所需的实现[因此,字节或长*
必须能够识别任何无符号字符],或者程序员只需要转换为联合类型指针,这些指针将满足其中每个组成部分的每个对齐要求
不,指向T
的指针可以指向任何包含T
的联合体,不一定相反。据我所知,联合体的对齐要求甚至可能比其所有成员的对齐要求更严格。OT:`它应该是printf(“%p\n”,(void*)bl[I];
而不是printf(“%lu\n”,bl[I])
@alk:代码在一个重要的细节上是错误的——它从未将bl[i]
传递给将使用它的代码。感谢您的评论——我修复了上面的代码。我希望\u Alignof(someUnion)
将报告允许使用联合体所有成员的对齐方式。问题本质上是,如果只访问满足对齐要求的成员,是否可以合法创建联合体类型的指针,以满足部分但不是所有成员的对齐要求。@supercat:正如我所说,a一旦指针转换为与目标错误对齐的指针,就会违反对齐要求。是否取消对其的引用无关紧要。如果您想假设平台中指向未对齐地址的指针没有问题(但通过此类指针进行访问是有问题的),代码已经定义了,我想……虽然从技术上讲它仍然会违反严格的别名(或者可能不会),但这是C11标准afaik中目前存在的一个公开问题。我认为这是可能的,尽管我很好奇标准中是否有任何东西可以澄清。从概念上讲,如果一个方法接受一个指针,如果它指向一种数据就必须对齐,但如果它指向另一种类型就不需要对齐,那么拥有它似乎很好它接受一个指针类型,可以将该消息传递给程序员,但是如果标准不允许,那么接受一个字节对齐类型似乎更好。我也可以看到一些关于严格别名的有趣问题。作为一个常见的现实场景,给定typedef union{uint8_t bb[4];uint32_t l;}QUAD;
,编译器是否需要假设如果uint32_t
的地址可能已被强制转换为QUAD*
,则接受QUAD*
的方法可能会影响uint32_t
?后一种类型的场景似乎非常常见。如果有foo
类型为无符号字符的变量*
,则任何无符号字符*
类型的变量都可以将其地址提取并存储在foo
中,这样*foo
就可以识别该变量。问题是,对于每一个无符号字符
类型的foo2
变量,是否可以使其foo2->b
将标识该变量,或者如果只能为恰好位于单词对齐地址的无符号字符
变量创建此类指针。我似乎不理解这个问题。foo2->b
是变量。它将如何标识另一个变量foo
?@supercatAssuming“这样的指针”指的是键入的BYTE\u或\u LONG*
:是的,它的成员b
s会像键入的l
一样对齐,也就是LONG
s。@supercatOk,我终于得到了问题。我会删除我的答案。@supercathou不应该疯狂地投掷。-@supercat
void test()
{
long l = encode_long(12345678); // Platform-dependent; could return
// (it<<8), (it & 16777215), etc.
char b[2] = {12,34};
BYTE_OR_LONG *bl[3];
bl[0] = (BYTE_OR_LONG*)&l;
bl[1] = (BYTE_OR_LONG*)b;
bl[2] = (BYTE_OR_LONG*)(b+1);
for (int i=0; i<3; i++)
printf("%lu\n", get_byte_or_long(bl[i]));
}