Xfc*_*ce4 0 c struct memory-management
考虑结构:
struct MainStruct {
struct A a;
struct B b;
struct C c;
};
Run Code Online (Sandbox Code Playgroud)
通常,编译器应该将 a、b 和 c 依次放入内存中并进行一定的对齐。
但是,如果我想让 a、b 和 c 的变量始终以 mainStruct 内的精确偏移量开始,而与它们的大小无关,该怎么办?“在编译时”执行此操作的便捷方法是什么?
举个例子: mainStruct 总共可能有 256 个字节,而a总是从 开始&mainStruct,b总是从 开始&mainstruct + 100,c总是从 开始&mainStruct + 179。
编辑:
mainStruct 的地址可能是可变的。这里重要的一点是偏移量始终是恒定的。每当我定义类型的变量时Struct MainStruct,该变量应该始终具有相同的内存布局,并且内部结构具有恒定的偏移量。
这可以通过匿名联合和编译器功能来打包结构和联合来完成。由于#pragma pack(1)似乎可以与 MSVC、GCC 和 Clang 一起使用,因此这里有一个简单的解决方案:
#include <stddef.h> // Included for offsetof macro.\n#include <stdio.h>\n\n\nstruct A { char c; int whatever; };\nstruct B { char c; int whatever; };\nstruct C { char c; int whatever; };\n\n\n#define MemberBOffset 100\n#define MemberCOffset 179\n\n#pragma pack(push, 1)\nunion MainStruct\n{\n struct\n {\n // No padding.\n struct A a;\n };\n struct\n {\n char paddingB[MemberBOffset];\n struct B b;\n };\n struct\n {\n char paddingC[MemberCOffset];\n struct C c;\n };\n};\n#pragma pack(pop)\n\n\nint main(void)\n{\n printf("Offset of member a = %td.\\n", offsetof(union MainStruct, a));\n printf("Offset of member b = %td.\\n", offsetof(union MainStruct, b));\n printf("Offset of member c = %td.\\n", offsetof(union MainStruct, c));\n}\nRun Code Online (Sandbox Code Playgroud)\n请注意,这通过使用更少的结构/联合嵌套和使用匿名结构改进了Henry Gilbert\xe2\x80\x99s 答案中的解决方案,以便可以以自然方式访问成员,例如foo.b代替foo.memberData.b.
如果struct MainStruct需要而不是union MainStruct,则可以将联合设为匿名并嵌套在struct MainStruct. 或者,typedef可以使用 a。
上面期望成员的偏移量a为零,并且其他偏移量不为零。如果情况并非总是如此,我们可以修饰:
#define MemberAOffset 0\n#define MemberBOffset 100\n#define MemberCOffset 179\n\n#pragma pack(push, 1)\nunion MainStruct\n{\n struct\n {\n #if 0 < MemberAOffset\n char paddingA[MemberAOffset];\n #endif\n struct A a;\n };\n struct\n {\n #if 0 < MemberBOffset\n char paddingB[MemberBOffset];\n #endif\n struct B b;\n };\n struct\n {\n #if 0 < MemberCOffset\n char paddingC[MemberCOffset];\n #endif\n struct C c;\n };\n};\n#pragma pack(pop)\nRun Code Online (Sandbox Code Playgroud)\n该#pragma pack指令具有重大影响;它会影响 内部声明的任何结构union MainStruct。也就是说,如果struct A a;我们有 ,而不是struct A { char c; int i; } a;,它将打包struct A而不是使用其自然填充。在指令之前声明struct A、struct B、 和可以避免这种情况。struct C然而,GCC 和 Clang 的另一种选择是使用更精细的__attribute__表示法,而不使用#pragma pack指令。
union __attribute__((__packed__)) MainStruct\n{\n struct __attribute__((__packed__))\n {\n #if 0 < MemberAOffset\n char paddingA[MemberAOffset];\n #endif\n struct A a;\n };\n struct __attribute__((__packed__))\n {\n #if 0 < MemberBOffset\n char paddingB[MemberBOffset];\n #endif\n struct B b;\n };\n struct __attribute__((__packed__))\n {\n #if 0 < MemberCOffset\n char paddingC[MemberCOffset];\n #endif\n struct C c;\n };\n};\nRun Code Online (Sandbox Code Playgroud)\n