C struct/union with explicit (manual) field layout?
What is the C equivalent of this C# code?
[StructLayout(LayoutKind.Explicit)]
struct Test
{
[FieldOffset(0)] int a; // Integer at byte offset 0
[FieldOffset(1)] int b; // Integer at byte offset 1
[FieldOffset(3)] int c; // Integer at byte offset 3
};
(I don't care if 开发者_StackOverflowit's non-portable, e.g. int
is assumed to be 4 bytes, etc.)
This seems to work fine under Visual Studio:
#pragma pack(push)
#pragma pack(1)
typedef union
{
int a;
struct
{
char unused0;
int b;
};
struct
{
char unused1;
char unused2;
char unused3;
int c;
};
} Test;
#pragma pack(pop)
Here is a macro that should work across clang, gcc and msvc (haven't tested the msvc version):
#define YDUMMY(suffix, size) char dummy##suffix[size]
#define XDUMMY(suffix, size) YDUMMY(suffix, size)
#define DUMMY(size) XDUMMY(__COUNTER__, size)
#ifdef __GNUC__
#define EXPLICIT_UNION_START(name) union Test {
#define EXPLICIT_UNION_END() };
#define EXPLICIT_OFFSET_FIELD(foff, ftype, fname) struct __attribute__((packed)) { DUMMY(foff); ftype fname; };
#elif defined(_MSC_VER)
#define EXPLICIT_UNION_START(name) #pragma pack(push, 1) \
union Test {
#define EXPLICIT_UNION_END() }; \
#pragma pack(pop)
#define EXPLICIT_OFFSET_FIELD(foff, ftype, fname) struct { DUMMY(foff); ftype fname; };
#else
#error "What compiler is this?"
#endif
EXPLICIT_UNION_START(Test)
EXPLICIT_OFFSET_FIELD(0, int, a)
EXPLICIT_OFFSET_FIELD(1, int, b)
EXPLICIT_OFFSET_FIELD(3, int, c)
EXPLICIT_UNION_END()
Thanks to unnamed fields, the syntax to access your defined fields is not polluted by dummy names:
int main() {
union Test t;
t.b = 13;
printf("offset a = %zx\n", offsetof(union Test, a));
printf("offset b = %zx\n", offsetof(union Test, b));
printf("offset c = %zx\n", offsetof(union Test, c));
printf("t.b = %d\n", t.b);
return 0;
}
How about this.
union u_t {
struct {
int V;
} a;
struct {
byte dummy;
int V;
} b;
struct {
byte dummy1;
byte dummy2;
byte dummy3;
int V;
} c;
};
The dummy fields are used to force offsets. I think some compilers can force field or struct alignment, so you need to insure when you compile, that option is off. See the pragma pack directive. The way to get to the a, b, c values is to reference the V field within each respective struct in the union. Eg if u is of type u_t, then
u.c.V = 17;
You can do this with a union, perhaps with some #defines to simplify the usage.
union Test {
struct {
int V_a;
} s_a;
struct {
char V_a;
int V_b;
} S_b;
struct {
char V_a;
short V_b;
int V_c;
} S_c;
#define a S_a.V_a
#define b S_b.V_b
#define c S_c.V_c
};
Not exactly what you asked for, but you should be able achieve similar effect using bit fields.
Also, for Visual C++, it might be worth looking at: __declspec(align(#))
or #pragma pack
.
Alternative to using the union is to instead use methods to access the values, as you probably should be doing anyway. Although it's C++, where you asked for C - but I'm assuming C++ is fine based on your use of VC++.
#ifdef __cplusplus
struct Test {
int a() {
return *(int*)&values_[0];
}
void a(int value) {
*(int*)&values_[1] = value;
}
int b() {
return *(int*)&values_[1];
}
void b(int value) {
*(int*)&values_[1] = value;
}
int c() {
return *(int*)&values_[3];
}
void c(int value) {
*(int*)&values_[3] = value;
}
private:
char[8] values_;
};
#endif
精彩评论