C 是否可以使用特定对齐方式打包局部变量?

C 是否可以使用特定对齐方式打包局部变量?,c,memory-management,C,Memory Management,代码: #包括 int main(){ INTA; printf(“%p\n”、&a); charb[10]; printf(“%p\n”、&b); INTC; printf(“%p\n”、&c); } 产出: 0061fefc 0061fef2 0061feec 很明显,b占用了12字节的内存,因为默认的内存对齐方式使得c的起始地址是4的倍数。是否可以禁用内存对齐?我知道,#pragma pack可以打包一个结构,它可以打包一个局部变量以使b只占用10个字节吗?这是一个让我感兴趣的面试问题

代码:

#包括
int main(){
INTA;
printf(“%p\n”、&a);
charb[10];
printf(“%p\n”、&b);
INTC;
printf(“%p\n”、&c);
}
产出:

0061fefc
0061fef2
0061feec

很明显,
b
占用了12字节的内存,因为默认的内存对齐方式使得
c
的起始地址是4的倍数。是否可以禁用内存对齐?我知道,
#pragma pack
可以打包一个结构,它可以打包一个局部变量以使
b
只占用10个字节吗?这是一个让我感兴趣的面试问题。任何帮助都将不胜感激

C标准没有提供任何设施来请求对象的轻松对齐,对于独立对象(不是结构成员的对象),这种功能几乎没有价值

有时使用标准C的扩展对结构进行打包,因为它们中的字节需要连续排列以用于某些特定用途,例如在网络消息中传输它们,或者因为当大量结构实例保存在内存中时,它们中的填充可能会浪费大量空间。对于单个独立对象,不会出现这种情况

显示的
char
数组不占用12个字节。它占用10个字节。其他两个字节要么未使用,要么被编译器用于其他在所检查的地址中不明显的目的。在结构中,填充字节被保留为不可用于其他用途,以提供所需的对齐方式。在这种情况下,可能会跳过字节以提供所需的对齐方式,但不会为此目的保留字节。如果需要两个字节的对象,编译器可以将其插入这些字节中


由于对齐要求而浪费的堆栈空间量通常很小,因为与结构成员不同,编译器可以自由地重新排列对象以有效地使用空间。而且堆栈指针通常必须仍然满足应用程序二进制接口(ABI)的对齐要求,因此,不管堆栈上对象的对齐要求如何,仍然需要一些对齐空间。

变量打包是实现定义的功能。因此,没有标准的方法来做到这一点

我也不认为这是可能的GCC,叮当声或MSVC

  • alignas
    属性((对齐))
    可以增加对齐,但不能减少对齐

  • \uuuu属性((packed))
    \pragma pack
    在结构之外似乎不起作用,尽管这表明:

packed
属性指定变量或结构字段应具有尽可能最小的对齐方式

叮当声输出类似的警告。MSVC默默地忽略那里的
#pragma pack


总而言之,这是一个糟糕的面试问题,因为它太具体了;了解这一点与成为一名优秀的程序员之间几乎没有什么关联(如果有的话)。虽然有时像这样的问题被用来探讨一个人对压力的承受能力:)

0061FEFC-0061FEF2=A
(而不是
C
)。你是说中间的那个是
0061ef0
吗?@WeatherVane
b
在前面填充,而不是后面,因为堆栈向下增长
0061fefc-0061FEC-4
=
C
(假设
sizeof(int)==4
)@rustyx
0061fef2
没有4字节的对齐方式,操作状态占用12字节,而不是10字节。@jl0x61面试问题到底是什么?任何打包都取决于编译器:C标准只提到位字段的打包,而没有提到变量存储的方式或位置。那么哪个编译器有问题呢?@WeatherVane:该标准确实说明了一些关于对象存储方式的问题。6.2.8讨论对准要求,并提供
\u Alignas
以请求更严格的对准。不要过分认为C标准只定义了一个抽象的计算模型。这是一个非常实用的文档。@rustyx:什么是“数据立方体”?我非常怀疑您的客户机在堆栈上有千兆字节的数据。@rustyx:正如我的回答所述,结构成员有时是打包的。它是独立的对象,这样做几乎没有或根本没有用。为了清楚起见,我会更新。
#include <stdio.h>
int main() {
    int a;
    printf("%p\n", &a);
    __attribute__ ((packed)) char b[10];
    printf("%p\n", &b);
    __attribute__ ((packed)) int c;
    printf("%p\n", &c);
}
warning: ‘packed’ attribute ignored [-Wattributes]
     __attribute__ ((packed)) char b[10];
                                       ^
warning: ‘packed’ attribute ignored [-Wattributes]
     __attribute__ ((packed)) int c;
                                  ^