我有一个API,其中包含一个公共结构A和一个内部结构B,并且需要能够将结构B转换为结构A。以下代码是否在C99(和VS 2010/C89)和C++03/C++11中合法且具有良好定义的行为?如果是,请解释什么使它具有良好的定义。如果不是,则转换这两个结构之间最有效和跨平台的方法是什么?
struct A {
uint32_t x;
uint32_t y;
uint32_t z;
};
struct B {
uint32_t x;
uint32_t y;
uint32_t z;
uint64_t c;
};
union U {
struct A a;
struct B b;
};
int main(int argc, char* argv[]) {
U u;
u.b.x = 1;
u.b.y = 2;
u.b.z = 3;
u.b.c = 64;
/* Is it legal and well defined behavior when accessing the non-write member of a union in this case? */
DoSomething(u.a.x, u.a.y, u.a.z);
return 0;
}
更新
我简化了示例并编写了两个不同的应用程序。其中一个基于memcpy,另一个使用union。
Union:
struct A {
int x;
int y;
int z;
};
struct B {
int x;
int y;
int z;
long c;
};
union U {
struct A a;
struct B b;
};
int main(int argc, char* argv[]) {
U u;
u.b.x = 1;
u.b.y = 2;
u.b.z = 3;
u.b.c = 64;
const A* a = &u.a;
return 0;
}
memcpy:
#include <string.h>
struct A {
int x;
int y;
int z;
};
struct B {
int x;
int y;
int z;
long c;
};
int main(int argc, char* argv[]) {
B b;
b.x = 1;
b.y = 2;
b.z = 3;
b.c = 64;
A a;
memcpy(&a, &b, sizeof(a));
return 0;
}
调试模式下的程序集剖析 [DEBUG] (Xcode 6.4, 默认C++编译器):
以下是调试模式下程序集中相关的差异。当我对发布版本进行剖析时,程序集没有差异。
Union:
movq %rcx, -48(%rbp)
memcpy:
movq -40(%rbp), %rsi
movq %rsi, -56(%rbp)
movl -32(%rbp), %edi
movl %edi, -48(%rbp)
注意:
基于union的示例代码会产生一个警告,指出变量'a'未被使用。由于分析的汇编代码来自调试模式,我不知道是否有任何影响。
struct C
是一个不完整的类型,这使得struct B
也成为了不完整的类型。这又导致union U
也是不完整的类型。在我所知道的范围内,没有办法将U/B暴露出来而隐藏C。你只能拥有指向不完整类型的指针。 - kaylumvolatile struct...
的联合 - 对一个结构体的更改被缓存在寄存器中,不会刷新到RAM,然后通过“另一侧”读取(旧的)RAM值。 - SF.