C++ malloc 如何理解对齐?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8752546/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 19:03:27  来源:igfitidea点击:

how does malloc understand alignment?

c++cmemory-alignment

提问by Chang

following excerpted from here

以下摘自这里

pw = (widget *)malloc(sizeof(widget));

allocates raw storage. Indeed, the malloc call allocates storage that's big enough and suitably aligned to hold an objectof type widget

pw = (widget *)malloc(sizeof(widget));

分配原始存储。实际上, malloc 调用分配的存储空间足够大且适当对齐以保存类型为 widget的对象

also see fast pImplfrom herb sutter, he said:

还看到了来自herb sutter的fast pImpl,他说:

Alignment. Any memory Alignment. Any memory that's allocated dynamically via new or malloc is guaranteed to be properly alignedfor objects of any type, but buffers that are not allocated dynamically have no such guarantee

对齐。任何内存对齐。任何通过 new 或 malloc动态分配的内存都可以保证为任何类型的对象正确对齐,但不是动态分配的缓冲区没有这样的保证

I am curious about this, how does malloc know alignment of the custom type?

我对此很好奇,malloc 如何知道自定义类型的对齐方式?

采纳答案by Kerrek SB

Alignment requirements are recursive: The alignment of any structis simply the largest alignment of any of its members, and this is understood recursively.

对齐要求是递归的:any 的对齐struct只是其任何成员的最大对齐,这可以递归理解。

For example, and assuming that each fundamental type's alignment equals its size (this is not always true in general), the struct X { int; char; double; }has the alignment of double, and it will be padded to be a multiple of the size of double (e.g. 4 (int), 1 (char), 3 (padding), 8 (double)). The struct Y { int; X; float; }has the alignment of X, which is the largest and equal to the alignment of double, and Yis laid out accordingly: 4 (int), 4 (padding), 16 (X), 4 (float), 4 (padding).

例如,假设每个基本类型的对齐方式都等于它的大小(这通常并不总是正确的),那么struct X { int; char; double; }它的对齐方式为double,它将被填充为 double 大小的倍数(例如 4 (int), 1(字符)、3(填充)、8(双)。在struct Y { int; X; float; }具有的取向X,这是最大的,等于所述对准double,并且Y被相应地布置:4(INT),4(填充),16(X),4(浮动),4(填充)。

(All numbers are just examples and could differ on your machine.)

(所有数字都只是示例,在您的机器上可能会有所不同。)

Therefore, by breaking it down to the fundamental types, we only need to know a handful of fundamental alignments, and among those there is a well-known largest. C++ even defines a type max_align_twhose alignment isthat largest alignment.

因此,通过将其分解为基本类型,我们只需要了解少数基本对齐方式,其中有一个众所周知的最大对齐方式。C++ 甚至定义了一种max_align_t对齐方式最大对齐方式的类型。

All malloc()needs to do is to pick an address that's a multiple of that value.

所有malloc()需要做的就是选择一个是该值倍数的地址。

回答by ruakh

I think the most relevant part of the Herb Sutter quote is the part I've marked in bold:

我认为 Herb Sutter 引述中最相关的部分是我用粗体标记的部分:

Alignment. Any memory Alignment. Any memory that's allocated dynamically via new or malloc is guaranteed to be properly aligned for objects of any type, but buffers that are not allocated dynamically have no such guarantee

结盟。任何内存对齐。任何通过 new 或 malloc 动态分配的内存都保证与任何类型的对象正确对齐,但未动态分配的缓冲区没有这样的保证

It doesn't have to know what type you have in mind, because it's aligning for anytype. On any given system, there's a maximum alignment size that's ever necessary or meaningful; for example, a system with four-byte words will likely have a maximum of four-byte alignment.

它不必知道您想到的是什么类型,因为它可以针对任何类型进行对齐。在任何给定的系统上,都有一个必要或有意义的最大对齐大小;例如,具有四字节字的系统可能最多有四字节对齐。

This is also made clear by the malloc(3)man-page, which says in part:

这也被明确malloc(3)手册页,它说部分:

The malloc()and calloc()functions return a pointer to the allocated memory that is suitably aligned for any kind of variable.

malloc()calloc()函数返回一个指针,该对齐适当分配的内存用于任何类型的变量

回答by Greg Hewgill

The only information that malloc()can use is the size of the request passed to it. In general, it might do something like round up the passed size to the nearest greater (or equal) power of two, and align the memory based on that value. There would likely also be an upper bound on the alignment value, such as 8 bytes.

唯一malloc()可以使用的信息是传递给它的请求的大小。通常,它可能会执行一些操作,例如将传递的大小四舍五入到最接近的大于(或等于)2 的幂,并根据该值对齐内存。对齐值也可能有一个上限,例如 8 个字节。

The above is a hypothetical discussion, and the actual implementation depends on the machine architecture and runtime library that you're using. Maybe your malloc()always returns blocks aligned on 8 bytes and it never has to do anything different.

以上是假设性讨论,实际实现取决于您使用的机器架构和运行时库。也许你malloc()总是返回 8 个字节对齐的块,它永远不必做任何不同的事情。

回答by Pubby

1) Align to the least common multiple of all alignments. e.g. if ints require 4 byte alignment, but pointers require 8, then allocate everything to 8 byte alignment. This causes everything to be aligned.

1) 对齐到所有对齐的最小公倍数。例如,如果整数需要 4 字节对齐,而指针需要 8,则将所有内容分配为 8 字节对齐。这会导致所有内容对齐。

2) Use the size argument to determine correct alignment. For small sizes you can infer the type, such as malloc(1)(assuming other types sizes are not 1) is always a char. C++ newhas the benefit of being type safe and so can always make alignment decisions this way.

2) 使用 size 参数来确定正确的对齐方式。对于小尺寸,您可以推断类型,例如malloc(1)(假设其他类型的尺寸不是 1)始终是字符。C++new具有类型安全的优点,因此可以始终以这种方式做出对齐决策。

回答by Patrick Fromberg

Previous to C++11 alignment was treated fairly simple by using the largest alignment where exact value was unknown and malloc/calloc still work this way. This means malloc allocation is correctly aligned for any type.

在 C++11 之前,通过使用最大对齐方式处理相当简单,其中确切值未知,并且 malloc/calloc 仍然以这种方式工作。这意味着 malloc 分配对于任何类型都正确对齐。

Wrong alignment may result in undefined behavior according to the standard but I have seen x86 compilers being generous and only punishing with lower performance.

根据标准,错误的对齐可能会导致未定义的行为,但我看到 x86 编译器很慷慨,只会以较低的性能进行惩罚。

Note that you also can tweak alignment via compiler options or directives. (pragma pack for VisualStudio for example).

请注意,您还可以通过编译器选项或指令调整对齐方式。(例如 VisualStudio 的编译指示包)。

But when it comes to placement new, then C++11 brings us new keywords called alignofand alignas.Here is some code which shows the effect if compiler max alignment is greater then 1. The first placement newbelow is automatically good but not the second.

但是当谈到放置 new 时,C++11 为我们带来了称为alignofalignas 的新关键字下面是一些代码,显示了编译器最大对齐大于 1 时的效果。下面的第一个位置 new自动良好,但不是第二个。

#include <iostream>
#include <malloc.h>
using namespace std;
int main()
{
        struct A { char c; };
        struct B { int i; char c; };

        unsigned char * buffer = (unsigned char *)malloc(1000000);
        long mp = (long)buffer;

        // First placment new
        long alignofA = alignof(A) - 1;
        cout << "alignment of A: " << std::hex << (alignofA + 1) << endl;
        cout << "placement address before alignment: " << std::hex << mp << endl;
        if (mp&alignofA)
        {
            mp |= alignofA;
            ++mp;
        }
        cout << "placement address after alignment : " << std::hex <<mp << endl;
        A * a = new((unsigned char *)mp)A;
        mp += sizeof(A);

        // Second placment new
        long alignofB = alignof(B) - 1;
        cout << "alignment of B: " <<  std::hex << (alignofB + 1) << endl;
        cout << "placement address before alignment: " << std::hex << mp << endl;
        if (mp&alignofB)
        {
            mp |= alignofB;
            ++mp;
        }
        cout << "placement address after alignment : " << std::hex << mp << endl;
        B * b = new((unsigned char *)mp)B;
        mp += sizeof(B);
}

I guess performance of this code can be improved with some bitwise operations.

我想可以通过一些按位运算来提高这段代码的性能。

EDIT: Replaced expensive modulo computation with bitwise operations. Still hoping that somebody finds something even faster.

编辑:用按位运算替换了昂贵的模计算。仍然希望有人能更快地找到一些东西。

回答by John Paul

malloc has no knowledge of what it is allocating for because its parameter is just total size. It just aligns to an alignment that is safe for any object.

malloc 不知道它正在分配什么,因为它的参数只是总大小。它只是对齐对任何对象都是安全的对齐方式。