结构填充可靠性

时间:2017-10-26 09:03:59

标签: c dll dllimport

在C和C ++中,我们被教会将结构填充视为特定于编译器,因此我们避免依赖序列化等事情。

另一方面,每当我们链接到第三方动态库或共享对象时,我们都依赖于一致的结构填充。

我们来自<windows.h>

的示例
typedef struct _SECURITY_ATTRIBUTES {
  DWORD  nLength;
  LPVOID lpSecurityDescriptor;
  BOOL   bInheritHandle;
} SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES;

HANDLE WINAPI CreateThread(
  _In_opt_  LPSECURITY_ATTRIBUTES  lpThreadAttributes,
  _In_      SIZE_T                 dwStackSize,
  _In_      LPTHREAD_START_ROUTINE lpStartAddress,
  _In_opt_  LPVOID                 lpParameter,
  _In_      DWORD                  dwCreationFlags,
  _Out_opt_ LPDWORD                lpThreadId
);

我们不应该关心使用哪个编译器来创建Kernel32.dll,但是编译器定义的结构填充意味着如果使用了不同的编译器,那么Kernel32.dll可能会取消引用_SECURITY_ATTRIBUTES指针与我们的应用程序包装它的方式不同。

  • 我是否可以解释为什么可以将结构指针传递给第三方DLL而不知道它们的结构填充?
  • 对于动态加载的DLL / SO(使用LoadLibrarydlopen),相同的基本原理是否有效?
  • 如果我们使用#pragma pack,所有这些问题都会消失吗?
  • 如果是这样,#pragma pack会成为结构序列化的可靠解决方案吗?

1 个答案:

答案 0 :(得分:2)

从语言角度来看,你是完全正确的。填充和结构布局是一个实现细节,编译器可以自由选择。

但实际上,要使编译器在任何特定平台上都有用,它必须遵循平台ABI。如果有人试图生成一个不遵守平台ABI的编译器,那将完全没用。

因此,您可以安全地假设您使用的任何编译器都将与平台ABI兼容。你找不到任何可行的编译器。