6

由于我之前的问题没有成功(“使用 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 拥有自己的容器,针对天知道的情况进行了优化。我不应该在这里表​​达我的意见,因为它不是基督教的。

4

1 回答 1

1

只需修复 C++ 端的对齐问题。x86 代码应该没有理由在 8 字节对齐时崩溃,x64 也不应该在 4 字节对齐时崩溃。#pragma pack(push,4)将是一个合适的方法。您可能需要另一个#pragma pack用于内部 SSE 代码,但该代码不应暴露给 .Net AnyCPU 代码。

如果您收到数百个警告(当然忽略性能警告),那么编译器同意我的评估,即您的代码是可疑的。

于 2013-04-23T08:05:03.567 回答