2

我注意到,当在结构周围使用#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,这意味着编译指示也对结构产生了对齐(1)的影响。

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

4

2 回答 2

5

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

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

于 2020-02-24T08:51:40.457 回答
2

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

uint32_t正如评论中提到的,包装 1 对于具有单个成员的结构没有任何意义。但是,此编译指示确实将结构的对齐要求从 4 更改为 1。您可以使用 C11 进行测试_Alignof(TEST)

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

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

于 2020-02-24T10:40:35.953 回答