C编程-字节对齐(下)

Posted by 周思进 on January 12, 2020

C编程-字节对齐(上)讲到系统会对结构体进行默认字节对齐,当然也可以人为设定对齐方式,下面针对两种方式进行描述。

方式一、

通过#pragma指令对结构体设定对齐方式,如下:

#pragma pack(push, 1)   // 将原有对齐方式压栈,并设置新的对齐方式
typedef struct test{
	char a;
	int b;
	char c;
	double d;
}TEST;
#pragma pack(pop)   // 恢复原有对齐方式

上述示例如果未使用#pragma指令,其结构体大小是24字节,通过指定1字节对齐,其结构体最终大小则是14字节。

该方式尤其需要注意后面的恢复操作,否则包含该头文件之后的头文件,结构体字节对齐方式都会受影响。

方式二、

通过__attribute__((aligned(n)))设置类型属性,如下:

struct test {
    char a;
    short b;
}__attribute__((aligned(8)));

该结构体sizeof获取的大小是8字节。
__attribute__((aligned(n)))修改的是结构体最终需8字节对齐,内部变量对齐方式没变,即变量a占用1个字节,其后填充1个字节,变量b占用2个字节,其后填充4个字节。

如果结构体最大成员变量所占字节数大于n,则仍旧按最大成员变量长度对齐。 即如果上面是aligned(1),则结构体大小是4字节。

需要注意如下两种情况:

typedef struct testa {
    char a;
    short b;
}__attribute__((aligned(8))) TESTA;

typedef struct testb {
    char a;
    short b;
}TESTB __attribute__((aligned(8))) ;

TESTA和TESTB结构体的大小是不一样的,前者大小是8字节,而后者大小是4字节,因为前者__attribute__设置的属性针对的是结构体,而后者__attribute__设置的属性针对的是TESTB变量声明,即TESTB声明的变量需要8字节对齐,这就会存在如果声明TESTB变量类型数组,则会出现如下错误:

alignment of array elements is greater than element size

因为其结构体本身只有4字节,却要8字节对齐。

通过__attribute__((packed))设置类型属性,该选项取消编译器对结构体的优化操作,按实际字节数占用地址空间,如下:

struct test {
    char a;
    short b;
}__attribute__((packed));

得到的结构体大小就是3字节。


在了解了手动对齐的方式后,那一般什么情况下会需要手动设置对齐方式呢?

人为修改对齐方式,一般常见的就是修改成1字节对齐,这样修改的其中一点作用就是结构体占用的存储空间变小了,但读取效率上肯定会受影响。

另外常见的场景就是两方主机进行协议通信,其定义的协议结构体字段,不希望因为不同CPU可能处理字节对齐方式不同而有所差异,通过修改成1字节对齐,保证传输两方变量都是一一对应上的。

推荐阅读:
https://www.cnblogs.com/clover-toeic/p/3853132.html
https://gcc.gnu.org/onlinedocs/gcc-4.0.0/gcc/Type-Attributes.html#Type-Attributes