結構體對齊的規(guī)則詳解及C++代碼驗證
基本概念
CPU一次能讀取多少個字節(jié)的數(shù)據(jù)主要是看數(shù)據(jù)總線是多少位的,16位CPU一次能讀取2個字節(jié),32位CPU一次能讀取4個字節(jié),64位CPU一次能讀取8個字節(jié)。并且不能跨內存區(qū)間訪問,這句話的意思可以理解為,如果CPU是32位的話,那么可以將整個內存區(qū)間每4個字節(jié)分為一塊(BLOCK),每次讀取一個BLOCK的數(shù)據(jù)。
那么對于下面這個結構體:
struct st {
char c;
int i;
};
如果不進行對齊操作,char 的地址范圍0x00000000,int的地址范圍為0x00000001----0x00000004,int分布在兩個不同的BLOCK上,因此要讀取int需要兩次操作;如果進行4字節(jié)對齊,那么int的地址范圍為0x00000004----0x00000007,處在一個BLOCK上,因此只需一次讀取操作即可。缺點也顯而易見,多占用了3個字節(jié)。這也是典型的一種空間換時間的方法吧。
結構體對齊的規(guī)則
結構體對齊需要滿足以下三條規(guī)則,其中系統(tǒng)對齊模數(shù)在64位機器上默認為8字節(jié),32位機器上默認為4字節(jié)。通過預處理指令#pargma pack(N)可以修改系統(tǒng)模數(shù)為N個字節(jié)。
1、以結構體第一個元素的地址為起始地址,亦即結構體的起始地址。由上可知,第一個元素的偏移量為0;
2、結構體元素對齊原則:結構體成員的對齊模數(shù)為類型大小與系統(tǒng)對齊模數(shù)的較小者;結構體成員的偏移量(填充)為對齊模數(shù)的整數(shù)倍。
3、結構體大小對齊原則:結構體的對齊模數(shù)為結構體最大元素與系統(tǒng)對齊模數(shù)的較小者;結構體的大?。ㄌ畛洌榻Y構體對齊模數(shù)的整數(shù)倍。
程序驗證
測試環(huán)境為64位Windows ,VS2019,定義結構體st1,包含3個元素char,int,double,定義系統(tǒng)對齊模數(shù)為4個字節(jié)。
#include <iostream>
#pragma pack(4)
using Tsize = unsigned long long;
using namespace std;
struct st1 {
char c;
int i;
double db;
Tsize ch_offset() {
return Tsize((Tsize)&this->c - (Tsize)this);
}
Tsize int_offset() {
return Tsize((Tsize)&this->i - (Tsize)this);
}
Tsize double_offset() {
return Tsize((Tsize)&this->db - (Tsize)this);
}
};
int main() {
cout << "st1結構體大小" << sizeof(st1) << endl;
cout << "char 偏移量=" << st1().ch_offset() << endl;
cout << "int偏移量=" << st1().int_offset() << endl;
cout << "double偏移量=" << st1().double_offset() << endl;
return 0;
}
首先我們按照對齊規(guī)則來進行分析。第一個元素為char,類型大小為1個字節(jié),對齊模數(shù)min(1,4)=1,偏移量為0是對齊模數(shù)的整數(shù)倍,無需填充(從這里我們可以看到,第一個字節(jié)偏移量始終為0,是不需要填充的),下一個元素的偏移從1開始;第二個元素為int,類型大小4個字節(jié),對齊模數(shù)為4個字節(jié),不填充時偏移量為1,不是4的整數(shù)倍,因此這里需要填充3個字節(jié),使得int的偏移量為4,且下一個元素偏移從8開始;第三個元素是double,類型大小為8個字節(jié),對齊模數(shù)為4,偏移量從8開始,是4的整數(shù)倍,因此無需填充,占用8個字節(jié),因此結構體的大小為16個字節(jié)。運行程序輸出:

將系統(tǒng)對齊模數(shù)修改為1 【#pargma pack(1)】,這樣的話,任何情況下都無需填充(不足一個字節(jié)的類型視為一個字節(jié)),結構體的大小即為結構體元素大小之和。運行程序輸出:

將系統(tǒng)對齊模數(shù)修改為8 【#pargma pack(8)】,這樣的話,任何情況下都無需填充(不足一個字節(jié)的類型視為一個字節(jié)),結構體的大小即為結構體元素大小之和。運行程序輸出:

Emmm,好像和系統(tǒng)對齊模數(shù)為4時沒什么變化。那我們將int 和 double的順序換一下呢?
#include <iostream>
#pragma pack(8)
using Tsize = unsigned long long;
using namespace std;
struct st1 {
char c;
double db;
int i;
Tsize ch_offset() {
return Tsize((Tsize)&this->c - (Tsize)this);
}
Tsize int_offset() {
return Tsize((Tsize)&this->i - (Tsize)this);
}
Tsize double_offset() {
return Tsize((Tsize)&this->db - (Tsize)this);
}
};
int main() {
cout << "st1結構體大小" << sizeof(st1) << endl;
cout << "char 偏移量=" << st1().ch_offset() << endl;
cout << "double偏移量=" << st1().double_offset() << endl;
cout << "int偏移量=" << st1().int_offset() << endl;
return 0;
}

順序調了下,結構體就比原來大了8個字節(jié)!!!從中我們可以看出,將結構體元素從小到大排列,可以最大程度節(jié)省空間。
總結
本篇文章就到這里了,希望能給你帶來幫助,也希望您能夠多多關注腳本之家的更多內容!
相關文章
C++ 虛函數(shù)與純虛函數(shù)的使用與區(qū)別
本文主要介紹了C++ 虛函數(shù)與純虛函數(shù)的使用與區(qū)別,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-08-08
C++ opencv實現(xiàn)的把藍底照片轉化為白底照片功能完整示例
這篇文章主要介紹了C++ opencv實現(xiàn)的把藍底照片轉化為白底照片功能,結合完整實例形式詳細分析了C++使用opencv模塊進行圖片轉換操作的相關實現(xiàn)技巧,需要的朋友可以參考下2019-12-12

