简体   繁体   English

为什么编译器会抱怨对齐?

[英]Why does the compiler complain about the alignment?

I'd like to understand more about alignment. 我想更多地了解对齐方式。 Why does the Microsoft compiler (Visual Studio 2012 Express) complain about the alignment for the following snippet of code? 为什么Microsoft编译器(Visual Studio 2012 Express)会抱怨以下代码片段的对齐方式?

__declspec(align(16)) class Foo
{
public:
    virtual ~Foo() {}
    virtual void bar() = 0;
};

This is the warning the compiler presents to me: 这是编译器向我提出的警告:

warning C4324: 'Foo' : structure was padded due to __declspec(align())

It does not even matter whether or not the class has any virtual methods. 这个类是否有任何虚拟方法甚至无关紧要。 Even for an empty class the compiler complains with the same warning message. 即使对于空类,编译器也会使用相同的警告消息进行抱怨。 How is an empty class aligned? 空类是如何对齐的? How does the compiler pad this class? 编译器如何填充此类?

A warning does not necessarily mean you've done something wrong, but tells you that you might not have intended this behaviour. 警告并不一定意味着您做错了什么,但告诉您可能没有打算这样做。 Note that a compiler is allowed to warn about anything the developers considered worth warning about. 请注意,允许编译器警告开发人员认为值得警告的任何内容。 In principle, you could also be warned about compiling on Friday the 13th. 原则上,你也可以在13日星期五被警告编译。

In this specific case the assumption probably is that when you specify alignment, you don't want to make the class bigger. 在这种特定情况下,假设可能是当您指定对齐时,您不希望使类更大。 Therefore if the class gets bigger due to the alignment requirement you gave, it's not unlikely that you made a mistake. 因此,如果由于你给出的对齐要求而使类变得更大,那么你犯错误的可能性并不大。

Of course that leaves the question why the alignment requirement makes the class bigger. 当然,这就留下了为什么对齐要求使类更大的问题。 Now we are back in standards land (although the __declspec itself is a Microsoft extension and not standard). 现在我们回到了标准领域(虽然__declspec本身是Microsoft扩展而不是标准)。 The C++ standard requires that in arrays, the objects follow each other without any space in between. C ++标准要求在数组中,对象彼此跟随,其间没有任何空间。 Therefore if your objects must be aligned to 16-byte boundaries, the object must have a size which is a multiple of 16. If the size of the members (both explicit and implicit) doesn't give the necessary size, the compiler has to add unused bytes to the object. 因此,如果对象必须与16字节边界对齐,则对象的大小必须是16的倍数。如果成员的大小(显式和隐式)都没有给出必要的大小,则编译器必须将未使用的字节添加到对象。 These bytes are called padding. 这些字节称为填充。 Note that this padding is present even in objects which are not members of arrays. 请注意,即使在不是数组成员的对象中也存在此填充。

Now your class only contains an implicit virtual pointer (because it contains virtual functions) which, depending on the architecture, probably is either 4 or 8 bytes large. 现在你的类只包含一个隐式虚拟指针(因为它包含虚函数),根据体系结构,它可能是4或8字节大。 Since you've requested 16 byte alignment, the compiler has to add 12 or 8 bytes of padding to get the size to a multiple of 16, which it would not have had to add without that manual alignment specification. 由于您已请求16字节对齐,因此编译器必须添加12或8字节的填充以使大小为16的倍数,如果没有手动对齐规范,则不必添加。 And this is what the compiler warns about. 这就是编译器警告的内容。

In x86 Foo needs 4 bytes, so a 12-byte pad is needed. 在x86中,Foo需要4个字节,因此需要一个12字节的填充。 In x64 Foo needs 8 bytes, so a 8-byte pad is needed. 在x64中,Foo需要8个字节,因此需要一个8字节的填充。

What this warning says is that the size of the class (as returned by sizeof ) has changed (increased) as a result of using the __declspec(align()) . 这个警告说的是,由于使用__declspec(align()) ,类的大小(由sizeof返回)已经改变(增加__declspec(align()) That may break things, thus the warning. 这可能会破坏事情,从而发出警告。

An empty class has a size, of course, and must be greater than 0, so it is at least 1. 当然,空类的大小必须大于0,因此它至少为1。

Normally the size doesn't change with the alignment, but in your case it does, because you specified an alignment that is bigger than the unpadded size of the class. 通常,大小不会随着对齐而改变,但在你的情况下确实如此,因为你指定的对齐方式大于类的无衬垫大小。 And remember that in C the alignment of a type cannot be smaller than its size, actually the size must be a multiple of the alignment, so the size is increased to match the alignment. 请记住,在C中,类型的对齐不能小于其大小,实际上大小必须是对齐的倍数,因此增加大小以匹配对齐。

Why must the size be a multiple of the alignment? 为什么尺寸必须是对齐的倍数? Well, imagine an array of this type: consecutive elements are required to be separated by exactly sizeof(T) , but each object must be in a memory address multiple of the alignment. 好吧,想象一下这种类型的数组:连续元素需要用sizeof(T)分隔,但每个对象必须在对齐的多个内存地址中。 The only solution to this equation is that sizeof(T) must be a (non-null) multiple of the alignment. 该等式的唯一解决方案是sizeof(T)必须是对齐的(非空)倍数。

When you increase the alignment of your structure using __declspec(align()) or alignas() , it not only causes your structure to be aligned stricter, but may have to pad your structure at the end, according to this rule : 当您使用__declspec(align())alignas()增加结构的对齐方式时,它不仅会导致您的结构更严格地对齐,而且可能必须根据此规则 填充结构:

The size of a structure is the smallest multiple of its alignment greater than or equal to the offset of the end of its last member. 结构的大小是其对齐的最小倍数大于或等于其最后一个成员的末尾的偏移量。

In other words, if you increase alignment of a structure to say, 16, you better make sure the size of your struct is also a multiple of 16, or you risk having your struct changing in size due to padding, which may cause your program to break (the compiler can't tell how much you rely on the size of your structs and whether you know about this rule, so it issues a warning). 换句话说,如果你将结构的对齐增加到16,你最好确保你的结构的大小也是16的倍数,否则你的结构会因填充而改变大小,这可能会导致你的程序打破(编译器无法判断你依赖于结构的大小,以及你是否了解这个规则,因此它会发出警告)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么编译器抱怨这不是constexpr? - Why does the compiler complain about this not being a constexpr? 为什么 xlc++ 编译器会抱怨强制转换右值? - Why does the xlc++ compiler complain about casting an rvalue? 为什么我的编译器会抱怨一个概念缺少模板参数? - Why does my compiler complain about a missing template argument for a concept? 为什么编译器会在这里抱怨函数歧义? - Why does the compiler complain about function ambiguity here? 为什么编译器会抱怨对constexpr函数的未定义引用,即使它是在另一个源文件中定义的? - Why does the compiler complain about undefined reference to a constexpr function even though it is defined in another source file? 默认模板参数:为什么编译器会抱怨没有指定模板参数? - Default template parameters: Why does the compiler complain about not specifying template argument? 为什么编译器抱怨f()不可见? - Why does compiler complain that f() is not visible? 为什么gcc抱怨我的循环? - Why does gcc complain about my loops? 为什么编译器不抱怨将char添加到char *? - Why doesn't the compiler complain about adding char to char*? 为什么编译器不抱怨catch子句? - Why the compiler doesn't complain about the catch clauses?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM