1

我正在尝试构建一个简单的链表,其中每个元素都将与某个圆形地址对齐。我尝试了以下代码(尽可能缩短为 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%x\n", (unsigned int)sizeof(element));
    while (current) {
        printf("*(%p) = %d\n", &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 也不会改变对齐(只有 sizeof)。 这个答案没有帮助,因为它是关于堆栈分配的。找不到任何其他来源来解释这一点。我对这个属性要求太多了吗?还是做错了什么?

提前致谢!

4

2 回答 2

4

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

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

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

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

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

§3.11p9 如果实现不支持特定上下文中特定扩展对齐的请求,则程序格式错误。此外,对于动态存储的运行时分配请求,其所请求的对齐不能被兑现,应被视为分配失败。

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

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

于 2013-10-08T16:04:18.630 回答
1
attribute(__aligned__())

太可怕了。我称之为错误。gcc 列表上没有任何吸引力。甚至不承认有人读过它。

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

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

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

posix_memalign() 或胸围

于 2017-07-21T04:41:58.177 回答