如果我有以下结构:
struct Foo { int a; };
代码是否符合C ++标准?我的意思是,它不能产生“未定义的行为”吗?
Foo foo;
int ifoo;
foo = *reinterpret_cast<Foo*>(&ifoo);
void bar(int value);
bar(*reinterpret_cast<int*>(&foo));
auto fptr = static_cast<void(*)(...)>(&bar);
fptr(foo);
答案 0 :(得分:10)
指向标准布局结构对象的指针,使用reinterpret_cast进行适当转换,指向其初始成员(或者如果该成员是位字段,则指向它所在的单位),反之亦然。
你的Foo是一个标准布局类。
所以你的第二次演员是正确的。
我不能保证第一个是正确的(并且我使用的架构中,char的对齐限制比仅包含char的结构更弱,在这样的架构上,这将是有问题的)。标准的保证是,如果你有一个指向int的指针,它真正指向结构的第一个元素,你可以将它重新解释为指向结构的指针。
同样地,如果它是reinterpret_cast,我看不到任何可以使你的第三个被定义的东西(我很确定一些ABI使用不同的约定来传递结构和基本类型,所以它非常可疑,我需要一个在标准中明确提到接受它)并且我很确定在指向函数的指针之间什么都不允许static_cast。
答案 1 :(得分:4)
只要您只访问结构的第一个元素,它就被认为是安全的,因为在结构的第一个成员之前没有填充。实际上,这个技巧例如在Objecive-C运行时中使用,其中泛型指针类型定义为:
typedef struct objc_object {
Class isa;
} *id;
并且在运行时,真正的对象(仍然是裸结构指针)具有这样的内存布局:
struct {
Class isa;
int x; // random other data as instance variables
} *CustomObject;
并且运行时使用此方法访问实际对象的类。
答案 2 :(得分:2)
Foo是一种普通的旧数据结构,这意味着它只包含您明确存储在其中的数据。在这种情况下:一个int。 因此int和Foo的内存布局是相同的。
你可以毫无问题地从一个到另一个进行类型转换。使用这种东西是一个聪明的想法是一个不同的问题。
PS: 此通常有效,但不一定是由于不同的对齐限制。见AProgrammer的答案。