【问题标题】:Clone existing structs with different alignment in Visual C++在 Visual C++ 中克隆具有不同对齐方式的现有结构
【发布时间】:2011-02-15 19:25:15
【问题描述】:

有没有办法在 Visual C++ 中克隆具有不同成员对齐方式的现有结构?

这是背景:

我使用一个 3rd-party 库,它定义了几个结构。为了填充结构,我将结构实例的地址传递给一些函数。不幸的是,函数只返回未对齐的缓冲区,因此某些成员的数据总是错误的。

/Zp 是无法选择的,因为它破坏了程序的其他部分。我知道#pragma pack 修改了以下定义的结构的对齐方式,但我宁愿避免将结构复制到我的代码中,因为库中的定义将来可能会发生变化。

示例代码:

图书馆.h:

结构 am_aligned { 字节数据1[10]; 超长数据2; }; 结构不变 { 字节数据1[9]; 整数数据2; };

test.cpp:

#include "库.h" // typedef alignment(1) struct am_aligned am_unaligned; int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { 字符缓冲区[20] = {}; for (int i = 0; i

am_unaligned是我的自定义声明,只在test.cpp有效。注释行当然不起作用。 untouched 应该仍然具有默认对齐方式。

instance.data20x0f0e0d0c,而 0x0d0c0b0a 是需要的。

感谢您的帮助!

【问题讨论】:

  • 可能解决这个问题的唯一方法是为这个类编写我自己的反序列化代码,并在将来更改类时进行更新。

标签: c class struct alignment


【解决方案1】:

不确定,也许 __declspec(align( number )) struct{...} 会有所帮助。更多关于MSDN

【讨论】:

    【解决方案2】:

    您应该在包含您使用的库的标头之前使用#pragma pack(以及之后,使用 push 和 pop)。这样您就不必自己定义结构了。

    #pragma pack(push, 1)
    #include <libraryheader.h>
    #pragma pack(pop)
    
    // You can now use the struct defined in the library
    

    确实,该库已使用给定的对齐方式进行编译。 您无法更改,它已经在二进制编译库中进行了硬编码。但是,当您编译文件时,您必须指示编译器,库中包含的结构将被定义并与另一个对齐方式一起使用。

    【讨论】:

    • 头文件包含数百个定义。我只需要修改其中几个。
    • 不同的对齐方式会改变你想要的结构的二进制定义,但是它会改变其他结构吗?还是会让它们保持不变?
    • 我希望库头文件中的所有原始结构都保持不变,但将特定结构克隆到我的实现中并且仅在我的文件中有效。
    • 我只是稍微改变了问题。希望现在更清楚了。 #pragma pack 方法是不可接受的。我使用在同一个 cpp 文件的库头中定义的其他默认对齐结构。该方法破坏了其余代码,类似于 /Zp。
    • 如果您不想重新定义结构,则在 pragma push/pop 之间包含库头 是您唯一的解决方案。请注意,这与 /Zp 非常不同,它也会更改所有 your 定义的包装。
    【解决方案3】:

    我怀疑唯一的问题可能是堆栈上缓冲区的起始地址未对齐。

    只需提供一个对齐的缓冲区而不是一个非对齐的缓冲区就可以了。

    几种简单的方法:

    • malloc 将缓冲区作为 mallocated 地址进行任何对齐都可以。
    • 将缓冲区定义为长缓冲区,它将被对齐(并使用 memcpy 复制而不是 for 循环并强制转换为 char *,无论如何它更快)。

    【讨论】:

    • 问题不在于与堆栈对齐。它与 struct am_aligned 的 data2 成员对齐。这个二进制库不使用填充,data2 从偏移量 10 开始,而用户程序使用填充,data2 从偏移量 12 开始。
    • @Didier:我明白这一点,但显然还有其他事情要做。首先,二进制库显然使用了一些填充,否则上述定义中的 data2 将从 9 开始,而不是 untouched 结构中的 10。 OP似乎对真实案例进行了一些过滤。此外,缓冲区的起始地址必须对齐,以使上述程序有任何机会运行。如果缓冲区起始地址未对齐,即使原始结构和未触及结构的大小相同,它也不会工作。
    • 对不起。 untouched 只是示例代码中的一个示例,并非真实案例。我真正的工作实际上是使用GetFontData 来获取字体表。表结构已在 FreeType 头文件中定义。 GetFontData 返回原始字节数组。由于上述原因,将字节数组转换为结构将失败。我不明白为什么缓冲区的起始地址必须对齐。
    • @Crend:我应该检查标准,但我相信有一些未指定的行为涉及将指针转换为具有不同对齐限制的另一个指针类型,然后通过赋值复制结构。如果您假设源内存和目标内存具有相同的对齐约束,则可以优化此类分配。我知道使用 memcpy 或连续成员个人分配的实现,在这里它应该可以正常工作。
    • @Crend:我找到了一些比我更清楚的参考资料:securecoding.cert.org/confluence/display/seccode/…
    猜你喜欢
    • 2020-11-23
    • 1970-01-01
    • 2012-05-02
    • 2018-11-21
    • 1970-01-01
    • 1970-01-01
    • 2021-11-13
    • 2016-11-17
    • 2016-04-15
    相关资源
    最近更新 更多