结构填充可靠性 在C和C++中,我们被教导要处理特定的编译器结构填充,所以我们避免依赖它来进行序列化之类的事情。

结构填充可靠性 在C和C++中,我们被教导要处理特定的编译器结构填充,所以我们避免依赖它来进行序列化之类的事情。,c,dll,dllimport,C,Dll,Dllimport,另一方面,每当我们链接到第三方动态库或共享对象时,我们都依赖于一致的结构填充 让我们以为例: typedef struct _SECURITY_ATTRIBUTES { DWORD nLength; LPVOID lpSecurityDescriptor; BOOL bInheritHandle; } SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES; HANDLE WINAPI Create

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

让我们以
为例:

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可能会取消引用
\u SECURITY\u ATTRIBUTES
指针,这与应用程序的打包方式不同

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

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

      然而,在实践中,为了使编译器在任何特定平台上都有用,它必须遵循平台ABI。如果有人试图生成一个不遵循ABI平台的编译器,那将是完全无用的


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

      有趣。因此,只要序列化的表单保持在同一平台上,结构实际上就可以序列化。这意味着它是可以找到的,但不能用于网络通信,因为您不能保证源/目标平台ABI与您自己的相匹配。(当然,您不能用指针序列化任何内容,但这是另一个主题)。32位和64位平台上的结构布局将有所不同。无论如何,您不希望通过网络或磁盘对结构进行blit。因此,在我看来,关于它的推理没有什么意义。为什么不将结构blit到磁盘?因为当您有多个体系结构时,它们将充满填充和结尾问题。winapi头会经历很多麻烦,以确保不会出错。在代码片段中部分可见,它不仅是void*,而且是LPVOID,不仅是unsigned,而是DWORD。等等,确定一个通用类型系统是关键。winapi中使用的许多结构都有一个字段,用于存储结构大小、额外保险和针对设计更改的弹性。安全属性没有,请注意nLength字段。是的,有很多pragma包。另一方面,每当我们链接到第三方动态库或共享对象时,我们都依赖于一致的结构填充。设计良好的界面不会依赖于结构填充的细节…@AndrewHenle这是否意味着在设计界面时,期望传递用户初始化的结构或结构指针是不好的做法?我经常看到库会为结构分配内存,然后在调用方法时期望指针作为句柄返回。@AndrewHenle在设计OS库时拒绝自己使用结构不是一个好主意idea@Stewart这是否意味着在设计界面时,期望传递用户初始化的结构或结构指针是错误的做法?如果由于不同的命令行编译器参数(如优化级别)而导致该结构的布局发生变化,这无疑是一种不好的做法。GCC非常擅长不提供此类选项。其他编译器,就不那么多了。