__attribute__((aligned(x)) 不适用于动态分配

__attribute__((aligned(x)) doesn't work on dynamic allocations

本文关键字:动态分配 适用于 不适用 attribute aligned      更新时间:2023-10-16

我正在尝试构建一个简单的链表,其中每个元素都将与某个圆形地址对齐。我尝试了以下代码(尽可能缩短为 SSCCE(:

#include "stdio.h"
#define N 10
typedef struct  __attribute__((aligned(0x100)) _element {
  int val;
  char padding[64];
  struct _element *next;
}  element;

int main() {
    element* head = new element;
    element* current = head;
    for (int i = 0; i < N; ++i) {
        current->val = i;
        if (i == N - 1)
            break;
        current->next = new element;
        current = current->next;
    }
    current->next = NULL;
    current = head;
    printf("sizeof(element) = 0x%xn", (unsigned int)sizeof(element));
    while (current) {
        printf("*(%p) = %dn", &current->val, current->val);
        current = current->next;
    }
    return 0;
}

使用 g++ 4.2.2 构建,没有优化,并生成:

sizeof(element) = 0x100
*(0x501010) = 0
*(0x501120) = 1
*(0x501230) = 2
*(0x501340) = 3
*(0x501450) = 4
*(0x501560) = 5
*(0x501670) = 6
*(0x501780) = 7
*(0x501890) = 8
*(0x5019a0) = 9

为什么地址未与0x100对齐?请注意,它确实影响了结构"大小",看起来它以某种方式被填充了,但它并没有像我想要的那样从对齐的地址开始。

从这个答案中,我了解到可能存在最大对齐方式,但即使将其降低到0x20也不会改变对齐方式(仅更改大小(。这个答案无济于事,因为它是关于堆栈分配的。找不到任何其他来源来解释这一点。我对这个属性的要求是否过高?还是做错了什么?

提前感谢!

你正在使用 gcc 的 C 扩展来定义你的对齐方式。这将影响对象的大小(必须是对齐方式的倍数(,并可能影响具有静态对齐方式的对象的存储布局,但仅限于链接器准备对齐此类对象的程度。它不会影响动态分配对象的对齐方式,即使在C++中也是如此。

C++ new运算符调用分配器函数来提供存储,然后通过调用对象构造函数继续初始化存储。该标准要求分配函数返回一个指针"适当对齐,以便它可以转换为具有基本对齐要求的任何完整对象类型的指针"。(§3.7.4.1p2(。缺省标准库全局分配器必须符合此要求 (§18.6.1(。"基本对齐要求"的定义是特定于实现的,但它必须至少与任何标量类型的对齐要求一样大,并且不需要更大。

C++标准指定的全局分配函数只有一个参数,即所请求对象的大小。它不会传递有关对象对齐方式或类型的任何信息,因此它无法执行特定于对齐方式的分配。

您可以自由地为给定类型定义分配函数,该函数可以考虑该类型的对齐方式。但是,它必须使用非标准(即系统特定(底层分配器,或者过度分配然后调整指针。(C++11 为此提供了一个标准库函数align

当我阅读标准时,C++11 要求如果对象类型的对齐方式超出基础分配器的能力,则new表达式失败:

§3.11p9 如果实现不支持在特定上下文中请求特定的扩展对齐,则程序格式不正确。此外,无法接受所请求的对齐的动态存储运行时分配请求应被视为分配失败。

这不适用于您的程序,因为您使用的是特定于 GCC 的面向 C 的对齐属性,当然不是 C++11,所以我想编译器有权调用分配器,该分配器将返回对齐不足的存储而不是抛出bad_alloc

顺便说一下,gcc 4.2.2刚刚庆祝了它的六岁生日。您应该考虑将其发送到小学并更新为更现代的东西。

attribute(__aligned__())

太可怕了。我称之为错误。在 gcc 列表中根本没有牵引力。甚至不承认有人读过它。

https://gcc.gnu.org/ml/gcc/2014-06/msg00308.html

请注意,您甚至无法检查您得到的内容是否对齐,因为它会错误地计算数学。

0xxxxxx30 % 0x40 == 0x0 //really? that's aligned to 64b?

posix_memalign(( 或胸围