# 改變結構體成員的字節對齊
## 例子
#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編譯的程序
- 其它
- 只做語法檢查
- 保存臨時文件
- 打開警告信息
- 指定語言類型
- 改變結構體成員的字節對齊