1

让我们考虑下面的声明。(Visual Studio 2010,警告级别 4)

#pragma pack(push, 2)
#define PADDING 1 // --- <case 1>
/*
#define PADDING 2 // --- <case 2>
*/
struct foo
{
    char a[PADDING];
    int b;
};

症状

如果将PADDING设置为<case 1>,肯定会产生C4121。但是对于<case 2>,它可以在没有任何警告的情况下编译。这两种情况具有相同的结构布局,“b”的偏移量为 2 个字节。
我期望 C4121 为<case 2>,因为“b”未在边界的倍数上对齐sizeof(int)。(来自MSDN。我找不到 2010 版本。)

问题

<case 1>我想知道只生产 C4121是否合理,因为结果结构布局(对齐)是相同的。
我错过了什么重要的东西吗?我应该忽略 C4121 吗?

附言

实际上,我曾经遇到过这种情况

  • 默认对齐值(8 个字节)
  • 指向未定义(仅前向声明)类的成员函数的指针(16 个字节)。

所以,我认为具体的对齐值不是重点。我已经编写了上面的示例代码以使事情变得简单。

4

2 回答 2

1

如果您忽略此警告,则必须记住:

当数据未在数倍于数据大小的边界上对齐时,性能可能会降低,并且如果将代码移植到 RISC 机器上,它将无法编译。

至少,您必须决定是否可以冒险抛出异常......

使用#pragma pack()来解决它是一个好方法,但有一个问题:

#pragma pack 指令只能用于减少项目默认打包结构的打包大小。如果您将项目打包设置为小于此值,这会导致库头文件的互操作性问题,例如使用 #pragma pack(8)。MSDN 文档[5] 指出,如果#pragma pack 打包大于或等于项目打包,它将被忽略。

出于这个原因,不应将项目打包设置为默认值 8 字节以外的任何值,因为它会破坏库头文件中使用的 #pragma pack 指令并导致结构之间的二进制不兼容。

但是也 :

x86 架构最初不需要对齐的内存访问,没有它仍然可以工作。

我会建议你避免这个警告,它会更安全......

解决此问题的方法是按照struct此处的建议颠倒成员的顺序:http: //msdn.microsoft.com/en-us/library/kabt0ka3%28v=vs.80%29.aspx

编辑: 另外一个链接解释了什么是数据结构对齐以及随之而来的问题:https ://en.wikipedia.org/wiki/Data_structure_alignment (我建议您阅读定义问题部分)

于 2013-07-17T10:15:11.623 回答
0

我认为这可能是编译器问题:

#pragma pack(push, 2)
struct foo
{
    char a[3];
    int b;
}; 

int main()
{
    foo f[2];
    cout << "sizeof(f) = " << sizeof(f) << endl;
    cout << "&f[0] =" << &f[0] << endl;
    cout << "&f[1] =" << &f[1] << endl;
    cout << "&f[0].b =" << &(f[0].b) << endl;
    cout << "&f[1].b =" << &(f[1].b) << endl;
}

使用 1 和 3 我得到警告,使用 2 没有,尽管使用 1 和 2 地址是相同的。

于 2013-07-17T11:17:08.500 回答