为什么#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"(启动代码)以及标准库函数可能需要分配超出程序员明确声明的变量。
值得注意的是,未对齐的访问使代码在许多系统上变慢,并可能导致程序在其他系统上崩溃。
我注意到当在结构周围使用#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"(启动代码)以及标准库函数可能需要分配超出程序员明确声明的变量。
值得注意的是,未对齐的访问使代码在许多系统上变慢,并可能导致程序在其他系统上崩溃。