0
#include <stdio.h>
int main(void)
{
    char c1 = '0';
    char _Alignas(double) c2 = '0';

    printf("char alignment:   %zd\n", _Alignof(char));
    printf("double alignment: %zd\n", _Alignof(double));
    printf("&c1: %p\n", &c1);
    printf("&c2: %p\n", &c2);

    return 0;
}

在我的环境中运行,结果是:

char alignment: 1
double alignment: 8
&c1: 000000000061FE1F
&c2: 000000000061FE18

由 gcc 版本 8.1.0 编译(x86_64-posix-seh-rev0,由 MinGW-W64 项目构建)。

我想知道为什么和之间的字节数&c2&c17,而不是 8(sizeof(double)在我的环境中)?

4

2 回答 2

2

为什么 char _Alignas 双倍大小不是 8?

对齐意味着地址是某个值的倍数。它与变量的大小无关。_Alignas(8)表示地址将是 8 的倍数,即以十六进制的 0 或 8 结尾

我想知道为什么 &c2 和 &c1 之间的字节是 7,而不是 8(在我的环境中 sizeof double)?

未指定变量在堆栈上的位置。编译器可以自由地放在c1前面或后面c2。这里唯一的要求是对齐c2必须是 8 的倍数。如果c1是 8 的倍数并且编译器选择在其后放置c2,那么将使用 7 个字节的填充。但它们显然可以放在c1前面c2,它们的地址只会相差 1。你可以很容易地看到每个编译器将变量放在不同的位置,不同的距离

有关更多详细信息,请阅读

于 2021-09-14T04:11:29.920 回答
1

对齐决定了地址的位置,而不是它们将占用多少空间。

Achar只占用 1 个字节,即使它在 8 字节边界上对齐。c1 和 c2 之间有 6 个未使用的字节。

通常,对齐方式和大小相同,或者对齐方式四舍五入到 2 的幂。这是因为在许多架构上,它可能需要多个 FETCH 指令才能从未对齐的内存地址中检索。

在您的情况下,c1在 1 字节边界上对齐,因此它被放置在堆栈上的第一个可用位置。

c2在 8 字节边界上对齐,因此它会跳过许多字节,直到地址在 8 字节边界上对齐。这意味着 (address % 8) == 0。如果c2是 type double,它将需要移动到下一个对齐的地址,提前 8 个字节,但由于它只是 achar它正好适合第一个 8 字节边界。(编辑:正如其他人指出的那样,编译器可以重新排列变量,并且在这种情况下可能会)

对齐可以大于或小于元素的大小。

在某些架构上,您只需在 2 或 4 字节边界上对齐。计算机根本无法解决“字节之间”的问题。不需要地址线,因此如果对齐 4 字节地址(并且始终读取 4 字节),则只需 14 条地址线即可寻址 2^16 字节的内存。这可以减少内存总线所需的大小。

于 2021-09-14T04:00:29.140 回答