为什么#pragma pack 也会影响结构自身的对齐方式?

Why #pragma pack also affects structs' own alignment?

我注意到当在结构周围使用#pragma pack 时,它内部的对齐方式不是唯一受影响的,而且结构本身的对齐方式也会发生变化。考虑以下因素:

#include <stdio.h>
#include <stdint.h>

#pragma pack(1)
typedef struct _TEST
{
    uint32_t a;
} TEST;
#pragma pack()

volatile uint8_t n;
TEST b;

int main()
{

    printf("Address %lX rem %lu\n", (long unsigned int)&b, (long unsigned int)(&b)%(sizeof(int)));  
    return 0;
}

您可以试试这里的代码:https://onlinegdb.com/BkebdxZEU

程序返回Address 601041 rem 1,这意味着pragma 也对结构体aligned(1) 产生了影响。

这是为什么?这是定义的行为吗?

结构的对齐受其成员对齐要求的影响。结构作为一个整体通常与其最大成员的对齐方式对齐。因为你的结构包含一个 uint32,如果你之前没有调用 #pragma,它会对齐到四个字节。

但是,使用 #pragma pack(1),您强制其所有成员所需的对齐为 1 字节(或无对齐),因此该结构现在可以从内存中的任何地址开始,而不一定是多个地址四个字节。

首先请注意,变量n不需要分配,因为它是volatile。由于您的程序没有引用此变量,因此编译器无法对它做任何有意义的事情,并且它没有被分配。从程序中删除 n 会产生相同的输出,因此这不能解释 "off by 1".

如评论中所述,打包 1 对于具有单个 uint32_t 成员的结构没有任何意义。然而,此 pragma 确实将结构的对齐要求从 4 更改为 1。您可以使用 C11 _Alignof(TEST) 进行测试。

这反过来意味着编译器可以自由地在它喜欢的任何地址分配结构。显然,在给定系统上,在与您的变量相同的内存段中分配了其他大小为 1 字节的东西,因此您的结构只是传递了下一个可用地址。 "CRT"(启动代码)以及标准库函数可能需要分配超出程序员明确声明的变量。

值得注意的是,未对齐的访问使代码在许多系统上变慢,并可能导致程序在其他系统上崩溃。