由于我之前的问题没有成功(“使用 x86/x64 C API 的 C# AnyCPU 库 - 打包结构、调用和回调”),我将写一个更简洁抽象的问题。
图片:
我工作的公司有一个可以移植到 64 位的软件。该软件由一个 BASE 库(带有 C API 的 C++)和 C API 上的两个包装器组成:一个 C++ 包装器和一个 .NET 包装器。
C++ BASE 库和 C++ WRAPPER 应该具有 x86/x64 构建配置。.NET WRAPPER 应该只有一个 AnyCPU 构建配置。
从 .NET WRAPPER 中选择正确的库已成功完成(两个 C++ BASE 库 (x86/x64) 都在两个单独的命名空间中加载,并且根据 IntPtr 的大小,在运行时调用正确的函数;这不一定需要两个库都在那里,但只有一个要使用)。
问题:
BASE 库中的所有结构都在 4 个字节上对齐:
#pragma pack(push,4)
为了让代码在 64 位上编译时没有警告,我添加了选择性对齐(C++ BASE 和 C++ WRAPPER 的工作就像魅力一样):
#ifdef WIN64
#pragma pack(push,8)
#else
#pragma pack(push,4)
#endif
问题与 .NET 中的结构有关:
[StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Unicode)]
internal struct DBConnectionSettings{...}
此结构不能有选择性打包,因为 AnyCPU 是唯一需要的 WRAPPER 配置。
在不同的 .NET 命名空间中创建在 8 个字节上对齐的单独结构非常困难(很多和很多性能损失)......然而,这可能是我们可能会发现完全有效的唯一解决方案。
回退到 x86 和 x64 的 4 字节对齐会发出很多警告,因为 100% 的结构对打包很敏感,尤其是对于一元运算符(问题只出现在 x64 解决方案配置中,4 字节对齐)。很多崩溃,除非我们添加虚拟成员,否则结构无法对齐。我应该提到,该结构是根据含义或与许可证/目标操作系统(ifdefs)相关的分组。为所有可能性添加填充(虚拟)成员将需要数月时间。
将所有内容对齐 8 个字节也不是一个解决方案,因为我们再次在整个地方崩溃 - 仅对于 x86,x64 工作得很好 - 结构对齐再次需要虚拟(填充)成员和基于大小的分组。
结论(问题):
1) 对于 x86 和 x64 解决方案配置,C++ 代码是否有可能对齐为 4?如何实现?
2) x86 和 x64 对齐的最佳选择是什么?指针大小绝对应该决定对齐方式(在我看来)。我们正在寻求 FAST 软件,不一定是内存效率高的(目前内存指纹在 x86 系统上介于 15mb 和 2gb 之间)。
3) 承载函数指针的结构对于.NET 和C 之间的互操作有什么特殊需求?
4)任何建议的替代方案都受到高度赞赏。
我们已经在这个互联网(我们星球上的那个)上搜索了一个多月,但我们一无所获。一些架构师恳求使用选择性打包 (4/8),而另一些架构师则认为该软件不是直截了当的,应该对其进行重构。做什么不是我的决定,但我可能会提出带有好论据的想法。该软件是在 2000 年代后期启动的,当时 STL 存在故障,因此 BASE 拥有自己的容器,针对天知道的情况进行了优化。我不应该在这里表达我的意见,因为它不是基督教的。