具有显式(手动)字段布局的C结构体/联合



这段c#代码的C等效是什么?

[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
};

(我不在乎它是否不可移植,例如int被认为是4字节,等等)

这似乎在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)

这是一个宏,应该工作在clang, gcc和msvc(尚未测试msvc版本):

#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()

由于未命名字段,访问已定义字段的语法不会受到虚拟名称的污染:

int main() {
    union Test t;
    t.b = 13;
    printf("offset a = %zxn", offsetof(union Test, a));
    printf("offset b = %zxn", offsetof(union Test, b));
    printf("offset c = %zxn", offsetof(union Test, c));
    printf("t.b = %dn", t.b);
    return 0;
}

这个怎么样

union u_t {
    struct {
        int V;
    } a;
    struct {
        byte dummy;
        int V;
    } b;
    struct {
        byte dummy1;
        byte dummy2;
        byte dummy3;
        int V;
    } c;
};

虚拟字段用于强制偏移。我认为一些编译器可以强制字段或结构对齐,所以你需要确保在编译时,那个选项是关闭的。参见pragma pack指令。获取a, b, c值的方法是在联合中的每个结构体中引用V字段。例如,如果u是u_t类型,则

  u.c.V = 17;

您可以使用联合,或者使用一些#定义来简化使用。

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
};

不完全符合您的要求,但您应该能够使用位字段实现类似的效果。

同样,对于Visual c++, __declspec(align(#))#pragma pack可能值得一看。

使用联合的另一种选择是使用方法来访问这些值,因为您可能无论如何都应该这样做。虽然它是c++,你要求的C -但我假设c++是好的基于你使用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

最新更新