I have an API with a publicly facing struct A and an internal struct B and need to be able to convert a struct B into a struct A. Is the following code legal and well defined behavior in C99 (and VS 2010/C89) and C++03/C++11? If it is, please explain what makes it well-defined. If it's not, what is the most efficient and cross-platform means for converting between the two structs?
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;
}
UPDATE
I simplified the example and wrote two different applications. One based on memcpy and the other using a 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;
}
Profiled Assembly [DEBUG] (Xcode 6.4, default C++ compiler):
Here is the relevant difference in the assembly for debug mode. When I profiled the release builds there was no difference in the assembly.
Union:
movq %rcx, -48(%rbp)
memcpy:
movq -40(%rbp), %rsi
movq %rsi, -56(%rbp)
movl -32(%rbp), %edi
movl %edi, -48(%rbp)
Caveat:
The example code based on union produces a warning regarding variable 'a' being unused. As the profiled assembly is from debug, I don't know if there is any impact.