# 改变结构体成员的字节对齐
## 例子
#include <stdio.h>
typedef struct
{
char a;
int b;
} ST_A;
int main(void)
{
printf("sizeof(ST_A)=%ld\n",sizeof(ST_A));
}
## 技巧
在上面的程序里,`ST_A`结构体的内存布局默认是这样的:
<table>
<tr>
<td>Offset</td>
<td>1byte</td>
<td>1byte</td>
<td>1byte</td>
<td>1byte</td>
</tr>
<tr>
<td>0</td>
<td>a</td>
<td>填充字节</td>
<td>填充字节</td>
<td>填充字节</td>
</tr>
<tr>
<td>4</td>
<td>b</td>
<td>b</td>
<td>b</td>
<td>b</td>
</tr>
</table>
编译执行,结果如下:
root@ubuntu:~$ gcc -g -o a a.c
root@ubuntu:~$ ./a
sizeof(ST_A)=8
使用gcc的"`-fpack-struct[=n]`"选项(“`n`”需要为`2`的倍数)可以改变成员的地址对齐。例如指定“`n=2`”时,将标明结构体成员的最大对齐地址为2。这样`ST_A`结构体中的成员`b`的地址将不再按照`4`字节对齐,内存布局变为:
<table>
<tr>
<td>Offset</td>
<td>1byte</td>
<td>1byte</td>
<td>1byte</td>
<td>1byte</td>
</tr>
<tr>
<td>0</td>
<td>a</td>
<td>填充字节</td>
<td>b</td>
<td>b</td>
</tr>
<tr>
<td>4</td>
<td>b</td>
<td>b</td>
<td></td>
<td></td>
</tr>
</table>
编译执行,结果如下:
root@ubuntu:~$ gcc -g -fpack-struct=2 -o a a.c
root@ubuntu:~$ ./a
sizeof(ST_A)=6
当不指定“`n`”时,将没有填充字节,所有成员将一个挨着一个排在一起:
<table>
<tr>
<td>Offset</td>
<td>1byte</td>
<td>1byte</td>
<td>1byte</td>
<td>1byte</td>
</tr>
<tr>
<td>0</td>
<td>a</td>
<td>b</td>
<td>b</td>
<td>b</td>
</tr>
<tr>
<td>4</td>
<td>b</td>
<td></td>
<td></td>
<td></td>
</tr>
</table>
编译执行,结果如下:
root@ubuntu:~$ gcc -g -fpack-struct -o a a.c
root@ubuntu:~$ ./a
sizeof(ST_A)=5
由于这个编译选项会导致ABI(Application Binary Interface)的改变,所以使用时一定要谨慎。
详情参见[gcc手册](https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html)
## 贡献者
nanxiao
- 信息显示
- 打印gcc预定义的宏信息
- 打印gcc执行的子命令
- 打印优化级别的对应选项
- 打印彩色诊断信息
- 打印头文件搜索路径
- 打印连接库的具体路径
- 预处理
- 生成没有行号标记的预处理文件
- 在命令行中预定义宏
- 在命令行中取消宏定义
- 汇编
- 把选项传给汇编器
- 生成有详细信息的汇编文件
- 调试
- 利用Address Sanitizer工具检查内存访问错误
- 利用Thread Sanitizer工具检查数据竞争的问题
- 连接
- 把选项传给连接器
- 设置动态连接器
- 函数属性
- 禁止函数被优化掉
- 强制函数inline
- 常见错误
- error: cast from ... to ... loses precision
- all warnings being treated as errors
- gdb无法调试gcc编译的程序
- 其它
- 只做语法检查
- 保存临时文件
- 打开警告信息
- 指定语言类型
- 改变结构体成员的字节对齐