C 为什么pragma包也会影响结构自身的对齐?

C 为什么pragma包也会影响结构自身的对齐?,c,memory-alignment,pragma-pack,C,Memory Alignment,Pragma Pack,我注意到,当在结构周围使用pragma包时,结构内部的对齐方式不仅会受到影响,而且结构本身的对齐方式也会发生变化。考虑以下事项: #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(

我注意到,当在结构周围使用pragma包时,结构内部的对齐方式不仅会受到影响,而且结构本身的对齐方式也会发生变化。考虑以下事项:

#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;
}

您可以尝试以下代码:

程序返回地址601041 rem 1,这意味着pragma在结构上也具有aligned1的效果


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

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


但是,使用pragma pack1,可以强制其所有成员的对齐方式为1字节或不对齐,因此结构现在可以从内存中的任何地址开始,而不一定是4字节的倍数。

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


但是,使用pragma pack1,可以强制其所有成员的对齐方式为1字节或不对齐,因此结构现在可以从内存中的任何地址开始,而不一定是4字节的倍数。

首先,请注意,变量n不需要分配,因为它是易失性的。由于您的程序没有引用此变量,编译器无法对其执行任何有意义的操作,因此它不会被分配。从程序中删除n会产生相同的输出,因此这不能解释off为1

正如注释中所提到的,打包1对于具有单个uint32\t成员的结构没有任何意义。但是,此杂注将结构的对齐要求从4更改为1。您可以使用C11 _AlignofTEST来测试这一点

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


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

首先,请注意,变量n不需要分配,因为它是易变的。由于您的程序没有引用此变量,编译器无法对其执行任何有意义的操作,因此它不会被分配。从程序中删除n会产生相同的输出,因此这不能解释off为1

正如注释中所提到的,打包1对于具有单个uint32\t成员的结构没有任何意义。但是,此杂注将结构的对齐要求从4更改为1。您可以使用C11 _AlignofTEST来测试这一点

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


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

C标准没有定义pragma,因此pragma是特定于编译器的。换句话说,这不是一个定义的行为。@Lundin我认为文档非常清楚:1 pragma packn只是设置新的对齐方式@Ctx是的,它明显地改变了对齐方式,但这并不能回答为什么它在在线编译器上以1的速度消失。没有为结构变量分配任何其他存储,那么为什么编译器只是为了它而选择一个未对齐的地址?@Lundin编译器并没有故意选择一个未对齐的地址,在我的例子中,变量b只是位于事务性内存附近,而事务性内存恰好结束于404030。然后使用下一个地址:404031@Ctx这可能是正确的答案:。特定系统上的bss布局。因为当我把它改为TEST b={1};从而将变量移动到.data,未对齐的地址就会消失。C标准没有定义pragma,因此pragma是特定于编译器的。换句话说,这不是一个定义的行为。@Lundin我认为文档非常清楚:1 pragma packn只是设置新的对齐方式@Ctx是的,它明显地改变了对齐方式,但这并不能回答为什么它在在线编译器上以1的速度消失。这个
re除了为struct变量分配外,没有其他分配,那么为什么编译器只是为了它而选择一个未对齐的地址呢?@Lundin编译器并没有故意选择一个未对齐的地址,在我的例子中,变量b只是位于事务性内存附近,而事务性内存恰好在404030处结束。然后使用下一个地址:404031@Ctx这可能是正确的答案:。特定系统上的bss布局。因为当我把它改为TEST b={1};因此,将变量移动到.data,未对齐的地址就会消失。那么,如果我们将pragmas放在结构定义中,行为会改变吗?例如,成员将在1上对齐,但结构将在4上对齐?@PaulOgilvie我不这么认为。pragma在即将发布的定义中设置结构成员的对齐方式,而不是直接设置结构本身的对齐方式。结构本身根据其成员的对齐方式进行对齐。因此,如果我们将pragmas放在结构定义中,行为会发生变化吗?例如,成员将在1上对齐,但结构将在4上对齐?@PaulOgilvie我不这么认为。pragma在即将发布的定义中设置结构成员的对齐方式,而不是直接设置结构本身的对齐方式。结构本身根据其成员的对齐方式进行对齐。