自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

面試??柬?xiàng)目易錯(cuò),長(zhǎng)文詳解C/C++中的字節(jié)對(duì)齊

開發(fā) 后端
現(xiàn)代計(jì)算機(jī)中內(nèi)存空間都是按照byte劃分的,從理論上講似乎對(duì)任何類型的變量的訪問都可以從任何地址開始,但實(shí)際情況是在訪問特定變量的時(shí)候經(jīng)常在特定的內(nèi)存地址訪問。

[[414243]]

引入主題,看代碼

我們先來看看以下程序

  1. #include <iostream> 
  2. using namespace std; 
  3. struct st1  
  4.  char a ; 
  5.  int  b ; 
  6.  short c ; 
  7. }; 
  8.  
  9. struct st2 
  10.   short c ; 
  11.   char  a ; 
  12.   int   b ; 
  13. }; 
  14.  
  15. int main() 
  16.  cout<<"sizeof(st1) -> "<<sizeof(st1)<<endl; 
  17.  cout<<"sizeof(st2) -> "<<sizeof(st2)<<endl; 
  18.   
  19.  return 0 ; 

 編譯的結(jié)果如下:

面試常考,項(xiàng)目易錯(cuò),長(zhǎng)文詳解C/C++中的字節(jié)對(duì)齊

問題來了,兩個(gè)結(jié)構(gòu)體的內(nèi)容一樣,只是換了個(gè)位置,為什么sizeof(st)的時(shí)候大小不一樣呢?

沒錯(cuò),這正是因?yàn)閮?nèi)存對(duì)齊的影響,導(dǎo)致的結(jié)果不同。對(duì)于我們大部分程序員來說,都不知道內(nèi)存是怎么分布的。

實(shí)際上因?yàn)檫@是編譯器該干的活,編譯器把程序中的每個(gè)數(shù)據(jù)單元安排在合適的位置上,導(dǎo)致了相同的變量,不同聲明順序的結(jié)構(gòu)體大小的不同。

幾種類型數(shù)據(jù)所占字節(jié)數(shù)

int,long int,short int的寬度和機(jī)器字長(zhǎng)及編譯器有關(guān),但一般都有以下規(guī)則(ANSI/ISO制訂的)

  1. sizeof(short int) <= sizeof(int)
  2. sizeof(int) <= sizeof(long int)
  3. short int至少應(yīng)為16位(2字節(jié))
  4. long int至少應(yīng)為32位

數(shù)據(jù)類型16位編譯器32位編譯器64位編譯器char1字節(jié)1字節(jié)1字節(jié)char*2字節(jié)4字節(jié)8字節(jié)short int2字節(jié)2字節(jié)2字節(jié)int2字節(jié)4字節(jié)4字節(jié)unsigned int2字節(jié)4字節(jié)4字節(jié)float4字節(jié)4字節(jié)4字節(jié)double8字節(jié)8字節(jié)8字節(jié)long4字節(jié)4字節(jié)8字節(jié)long long8字節(jié)8字節(jié)8字節(jié)unsigned long4字節(jié)4字節(jié)8字節(jié)

什么是對(duì)齊

現(xiàn)代計(jì)算機(jī)中內(nèi)存空間都是按照byte劃分的,從理論上講似乎對(duì)任何類型的變量的訪問都可以從任何地址開始,但實(shí)際情況是在訪問特定變量的時(shí)候經(jīng)常在特定的內(nèi)存地址訪問。

所以這就需要各類型數(shù)據(jù)按照一定的規(guī)則在空間上排列,而不是順序的一個(gè)接一個(gè)的排放,這就是對(duì)齊。內(nèi)存對(duì)齊又分為自然對(duì)齊和規(guī)則對(duì)齊。

對(duì)于內(nèi)存對(duì)齊問題,主要存在于struct和union等復(fù)合結(jié)構(gòu)在內(nèi)存中的分布情況,許多實(shí)際的計(jì)算機(jī)系統(tǒng)對(duì)基本類型數(shù)據(jù)在內(nèi)存中存放的位置有限制,它們要求這些數(shù)據(jù)的首地址的值是某個(gè)數(shù)M(通常是4或8);

對(duì)于內(nèi)存對(duì)齊,主要是為了提高程序的性能,數(shù)據(jù)結(jié)構(gòu),特別是棧,應(yīng)盡可能在自然邊界上對(duì)齊,經(jīng)過對(duì)齊后,cpu的內(nèi)存訪問速度大大提升。

自然對(duì)齊

指的是將對(duì)應(yīng)變量類型存入對(duì)應(yīng)地址值的內(nèi)存空間,即數(shù)據(jù)要根據(jù)其數(shù)據(jù)類型存放到以其數(shù)據(jù)類型為倍數(shù)的地址處。

例如char類型占1個(gè)字節(jié)空間,1的倍數(shù)是所有數(shù),因此可以放置在任何允許地址處,而int類型占4個(gè)字節(jié)空間,以4為倍數(shù)的地址就有0,4,8等。編譯器會(huì)優(yōu)先按照自然對(duì)齊進(jìn)行數(shù)據(jù)地址分配。

規(guī)則對(duì)齊

以結(jié)構(gòu)體為例就是在自然對(duì)齊后,編譯器將對(duì)自然對(duì)齊產(chǎn)生的空隙內(nèi)存填充無效數(shù)據(jù),且填充后結(jié)構(gòu)體占內(nèi)存空間為結(jié)構(gòu)體內(nèi)占內(nèi)存空間最大的數(shù)據(jù)類型成員變量的整數(shù)倍。

實(shí)驗(yàn)對(duì)比

首先看這個(gè)結(jié)構(gòu)體

  1. typedef struct test_32 
  2.  char a; 
  3.  short b; 
  4.  short c; 
  5.  char d; 
  6. }test_32; 

首先按照自然對(duì)齊,得到如下圖的內(nèi)存分布位置,第一個(gè)格子地址為0,后面遞增。

面試???,項(xiàng)目易錯(cuò),長(zhǎng)文詳解C/C++中的字節(jié)對(duì)齊

編譯器將對(duì)空白處進(jìn)行無效數(shù)據(jù)填充,最后將得到此結(jié)構(gòu)體占內(nèi)存空間為8字節(jié),這個(gè)數(shù)值也是最大的數(shù)據(jù)類型short的2個(gè)字節(jié)的整數(shù)倍。

如果稍微調(diào)換一下位置的結(jié)構(gòu)體

  1. typedef struct test_32 
  2.  char a; 
  3.  char b; 
  4.  short c; 
  5.  short d; 
  6. }test_32; 

同樣按照自然對(duì)齊如下圖分布

面試???,項(xiàng)目易錯(cuò),長(zhǎng)文詳解C/C++中的字節(jié)對(duì)齊

可以看到按照自然對(duì)齊,變量之間沒有出現(xiàn)間隙,所以規(guī)則對(duì)齊也不用進(jìn)行填充,而這里有顏色的方格有6個(gè),也就是6個(gè)字節(jié)

按照規(guī)則對(duì)齊,6字節(jié)是此結(jié)構(gòu)體中最大數(shù)據(jù)類型short的整數(shù)倍,因此此結(jié)構(gòu)體為6字節(jié),后面的空白不需理會(huì),可以實(shí)際編譯一下運(yùn)行,結(jié)果和分析一致為6個(gè)字節(jié)。

double的情況

我們知道32位處理器一次只能處理32位也就是4個(gè)字節(jié)的數(shù)據(jù),而double是8字節(jié)數(shù)據(jù)類型,這要怎么處理呢?

如果是64位處理器,8字節(jié)數(shù)據(jù)可以一次處理完畢,而在32位處理器下,為了也能處理double8字節(jié)數(shù)據(jù),在處理的時(shí)候?qū)?huì)把double拆分成兩個(gè)4字節(jié)數(shù)進(jìn)行處理,從這里就會(huì)出現(xiàn)一種情況如下:

  1. typedef struct test_32 
  2.  char a; 
  3.  char b; 
  4.  double c; 
  5. }test_32;  

這個(gè)結(jié)構(gòu)體在32位下所占內(nèi)存空間為12字節(jié),只能拆分成兩個(gè)4字節(jié)進(jìn)行處理,所以這里規(guī)則對(duì)齊將判定該結(jié)構(gòu)體最大數(shù)據(jù)類型長(zhǎng)度為4字節(jié),因此總長(zhǎng)度為4字節(jié)的整數(shù)倍,也就是12字節(jié)。

這個(gè)結(jié)構(gòu)體在64位環(huán)境下所占內(nèi)存空間為16字節(jié),而64位判定最大為8字節(jié),所以結(jié)果也是8字節(jié)的整數(shù)倍:16字節(jié)。這里的結(jié)構(gòu)體中的double沒有按照自然對(duì)齊放置到理論上的8字節(jié)倍數(shù)地址處,我認(rèn)為這里編譯器也有根據(jù)規(guī)則對(duì)齊做出相應(yīng)的優(yōu)化,節(jié)省了4個(gè)多余字節(jié)。

這部分各位可以按照上述規(guī)則自行分析測(cè)試。

數(shù)組

對(duì)齊值為:min(數(shù)組元素類型,指定對(duì)齊長(zhǎng)度)。但數(shù)組中的元素是連續(xù)存放,存放時(shí)還是按照數(shù)組實(shí)際的長(zhǎng)度。

如char t[9],對(duì)齊長(zhǎng)度為1,實(shí)際占用連續(xù)的9byte。然后根據(jù)下一個(gè)元素的對(duì)齊長(zhǎng)度決定在下一個(gè)元素之前填補(bǔ)多少byte。

嵌套的結(jié)構(gòu)體

假設(shè)

  1. struct A 
  2.   ...... 
  3.   struct B b; 
  4.   ...... 
  5. }; 

對(duì)于B結(jié)構(gòu)體在A中的對(duì)齊長(zhǎng)度為:min(B結(jié)構(gòu)體的對(duì)齊長(zhǎng)度,指定的對(duì)齊長(zhǎng)度)。

B結(jié)構(gòu)體的對(duì)齊長(zhǎng)度為:上述2種結(jié)構(gòu)整體對(duì)齊規(guī)則中的對(duì)齊長(zhǎng)度。舉個(gè)例子

  1. #include <iostream> 
  2. #include <cstdio> 
  3. using namespace std; 
  4.  
  5. #pragma pack(8) 
  6. struct Args 
  7.  char ch; 
  8.  double d; 
  9.  short st; 
  10.  char rs[9]; 
  11.  int i; 
  12. } args; 
  13.  
  14. struct Argsa 
  15.   char ch; 
  16.   Args test; 
  17.   char jd[10]; 
  18.   int i; 
  19. }arga; 
  20.  
  21. int main() 
  22.  cout<<"Args:"<<sizeof(args)<<endl; 
  23.  cout<<""<<(unsigned long)&args.i-(unsigned long)&args.rs<<endl; 
  24.  cout<<"Argsa:"<<sizeof(arga)<<endl; 
  25.  cout<<"Argsa:"<<(unsigned long)&arga.i -(unsigned long)&arga.jd<<endl; 
  26.  cout<<"Argsa:"<<(unsigned long)&arga.jd-(unsigned long)&arga.test<<endl; 
  27.  return 0; 

輸出結(jié)果:

面試???,項(xiàng)目易錯(cuò),長(zhǎng)文詳解C/C++中的字節(jié)對(duì)齊

改成#pragma pack (16)結(jié)果一樣,這個(gè)例子證明了三點(diǎn):

  • 對(duì)齊長(zhǎng)度長(zhǎng)于struct中的類型長(zhǎng)度最長(zhǎng)的值時(shí),設(shè)置的對(duì)齊長(zhǎng)度等于無用
  • 數(shù)組對(duì)齊的長(zhǎng)度是按照數(shù)組成員類型長(zhǎng)度來比對(duì)的
  • 嵌套的結(jié)構(gòu)體中,所包含的結(jié)構(gòu)體的對(duì)齊長(zhǎng)度是結(jié)構(gòu)體的對(duì)齊長(zhǎng)度

指針

主要是因?yàn)?2位和64位機(jī)尋址上,來看看例子

  1. //編譯器:https://tool.lu/coderunner/ 
  2. //來源:技術(shù)讓夢(mèng)想更偉大 
  3. //作者:李肖遙 
  4.  
  5. #include <iostream> 
  6. #include <cstdio> 
  7. using namespace std; 
  8.  
  9. #pragma pack(4) 
  10. struct Args 
  11.  int i; 
  12.  double d; 
  13.  char *p;  
  14.  char ch;  
  15.  int *pi; 
  16. }args; 
  17.  
  18. int main() 
  19. {     
  20.  cout<<"args length:"<<sizeof(args)<<endl; 
  21.  cout<<"args1:"<<(unsigned long)&args.ch-(unsigned long)&args.p<<endl; 
  22.  cout<<"args2:"<<(unsigned long)&args.pi-(unsigned long)&args.ch<<endl; 
  23.  return 0; 

結(jié)果如下

pack48length3240args188args248

內(nèi)存對(duì)齊的規(guī)則

1.數(shù)據(jù)成員對(duì)齊規(guī)則

結(jié)構(gòu)或聯(lián)合的數(shù)據(jù)成員,第一個(gè)數(shù)據(jù)成員放在offset為0的地方,以后每個(gè)數(shù)據(jù)成員的對(duì)齊按照#pragma pack指定的數(shù)值和這個(gè)數(shù)據(jù)成員自身長(zhǎng)度中,比較小的那個(gè)進(jìn)行。

例如struct a里存有struct b,b里有char,int ,double等元素,那b應(yīng)該從8的整數(shù)倍開始存儲(chǔ)。

2.結(jié)構(gòu)體作為成員

如果一個(gè)結(jié)構(gòu)里有某些結(jié)構(gòu)體成員,則結(jié)構(gòu)體成員要從其內(nèi)部"最寬基本類型成員"的整數(shù)倍地址開始存儲(chǔ)。

在數(shù)據(jù)成員完成各自對(duì)齊之后,結(jié)構(gòu)或聯(lián)合本身也要進(jìn)行對(duì)齊,對(duì)齊將按照#pragma pack指定的數(shù)值和結(jié)構(gòu)或聯(lián)合最大數(shù)據(jù)成員長(zhǎng)度中,比較小的那個(gè)進(jìn)行。

3.1&2的情況下注意

當(dāng)#pragma pack的n值等于或超過所有數(shù)據(jù)成員長(zhǎng)度的時(shí)候,這個(gè)n值的大小將不產(chǎn)生任何效果。

#pragma pack()用法詳解

  • 作用

指定結(jié)構(gòu)體、聯(lián)合以及類成員的packing alignment;

  • 語法

#pragma pack( [show] | [push | pop] [, identifier], n )

  • 說明
  1. pack提供數(shù)據(jù)聲明級(jí)別的控制,對(duì)定義不起作用;
  2. 調(diào)用pack時(shí)不指定參數(shù),n將被設(shè)成默認(rèn)值;
  3. 一旦改變數(shù)據(jù)類型的alignment,直接效果就是占用memory的減少,但是performance會(huì)下降;
  • 語法具體分析

1.show:可選參數(shù)

顯示當(dāng)前packing aligment的字節(jié)數(shù),以warning message的形式被顯示;

2.push:可選參數(shù)

將當(dāng)前指定的packing alignment數(shù)值進(jìn)行壓棧操作,這里的棧是the internal compiler stack,同時(shí)設(shè)置當(dāng)前的packing alignment為n;如果n沒有指定,則將當(dāng)前的packing alignment數(shù)值壓棧;

3.pop:可選參數(shù)

從internal compiler stack中刪除最頂端的record;如果沒有指定n,則當(dāng)前棧頂record即為新的packing alignment數(shù)值;如果指定了n,則n將成為新的packing aligment數(shù)值;如果指定了identifier,則internal compiler stack中的record都將被pop直到identifier被找到,然后pop出identitier,同時(shí)設(shè)置packing alignment數(shù)值為當(dāng)前棧頂?shù)膔ecord;如果指定的identifier并不存在于internal compiler stack,則pop操作被忽略;

4.identifier:可選參數(shù)

當(dāng)同push一起使用時(shí),賦予當(dāng)前被壓入棧中的record一個(gè)名稱;當(dāng)同pop一起使用時(shí),從internal compiler stack中pop出所有的record直到identifier被pop出,如果identifier沒有被找到,則忽略pop操作;

5.n:可選參數(shù)

指定packing的數(shù)值,以字節(jié)為單位;缺省數(shù)值是8,合法的數(shù)值分別是1、2、4、8、16

例子

  1. #include<stddef.h> 
  2. #include<iostream> 
  3. using namespace std; 
  4.   
  5. #pragma pack(4) 
  6. struct m    
  7.  int a;   
  8.  short b; 
  9.  int c; 
  10. }; 
  11. int main() 
  12.  cout <<"結(jié)構(gòu)體m的大小:"<< sizeof(m) << endl; 
  13.  cout << endl; 
  14.    
  15.   // 獲得成員a相對(duì)于m儲(chǔ)存地址的偏移量 
  16.  int offset_b = offsetof(struct m, a); 
  17.  
  18.  cout <<"a相對(duì)于m儲(chǔ)存地址的偏移量:"<< offset_b << endl; 
  19.  system("pause"); 
  20.  return 0; 
面試???,項(xiàng)目易錯(cuò),長(zhǎng)文詳解C/C++中的字節(jié)對(duì)齊

從運(yùn)行結(jié)果來看我們可以證實(shí)上面內(nèi)存對(duì)齊規(guī)則的第一條:第一個(gè)數(shù)據(jù)成員放在offset為0的地方。

現(xiàn)在咱來看看上面結(jié)構(gòu)體是如何內(nèi)存對(duì)齊的;先用代碼打印它們每個(gè)數(shù)據(jù)成員的存儲(chǔ)地址的偏移量

  1. #include<stddef.h> 
  2. #include<iostream> 
  3. using namespace std; 
  4.   
  5. #pragma pack(4) 
  6. struct m    
  7.  int a;   
  8.  short b; 
  9.  int c; 
  10. }; 
  11.  
  12.  
  13. int main() 
  14.  cout <<"結(jié)構(gòu)體m的大小:"<< sizeof(m) << endl; 
  15.  cout << endl; 
  16.  int offset_b = offsetof(struct m, a);// 獲得成員a相對(duì)于m儲(chǔ)存地址的偏移量 
  17.  int offset_b1 = offsetof(struct m, b);// 獲得成員a相對(duì)于m儲(chǔ)存地址的偏移量 
  18.  int offset_b2 = offsetof(struct m, c);// 獲得成員a相對(duì)于m儲(chǔ)存地址的偏移量 
  19.   
  20.  cout <<"a相對(duì)于m儲(chǔ)存地址的偏移量:"<< offset_b << endl; 
  21.  cout << "b相對(duì)于m儲(chǔ)存地址的偏移量:" << offset_b1 << endl; 
  22.  cout << "c相對(duì)于m儲(chǔ)存地址的偏移量:" << offset_b2 << endl; 
  23.   
  24.  //system("pause"); 
  25.  return 0; 
面試常考,項(xiàng)目易錯(cuò),長(zhǎng)文詳解C/C++中的字節(jié)對(duì)齊

在此c在結(jié)構(gòu)體中偏移量為8加上它自身(int)4個(gè)字節(jié),剛好是12(c的開始位置為8,所以要加它的4個(gè)字節(jié))

上面內(nèi)存結(jié)束為11,因?yàn)?-11,12是最大對(duì)齊數(shù)的整數(shù)倍,故取其臨近的倍數(shù),所以就取4的整數(shù)倍即12;

上圖中我用連續(xù)的數(shù)組來模仿內(nèi)存,如圖是它們的內(nèi)存對(duì)齊圖;

如果將最大內(nèi)存對(duì)齊數(shù)改為8,它將驗(yàn)證內(nèi)存對(duì)齊規(guī)則中的第3條。

如果將其改為2,會(huì)發(fā)生什么:我們來看看:

  1. #include<stddef.h> 
  2. #include<iostream> 
  3. using namespace std; 
  4.   
  5. #pragma pack(2) 
  6. struct m    
  7.  int a;   
  8.  short b; 
  9.  int c; 
  10. }; 
  11. int main() 
  12.  cout <<"結(jié)構(gòu)體m的大小:"<< sizeof(m) << endl; 
  13.  cout << endl; 
  14.  int offset_b = offsetof(struct m, a);// 獲得成員a相對(duì)于m儲(chǔ)存地址的偏移量 
  15.  int offset_b1 = offsetof(struct m, b);// 獲得成員a相對(duì)于m儲(chǔ)存地址的偏移量 
  16.  int offset_b2 = offsetof(struct m, c);// 獲得成員a相對(duì)于m儲(chǔ)存地址的偏移量 
  17.   
  18.  cout <<"a相對(duì)于m儲(chǔ)存地址的偏移量:"<< offset_b << endl; 
  19.  cout << "b相對(duì)于m儲(chǔ)存地址的偏移量:" << offset_b1 << endl; 
  20.  cout << "c相對(duì)于m儲(chǔ)存地址的偏移量:" << offset_b2 << endl; 
  21.   
  22.  //system("pause"); 
  23.  return 0; 
面試???,項(xiàng)目易錯(cuò),長(zhǎng)文詳解C/C++中的字節(jié)對(duì)齊

對(duì)于這個(gè)結(jié)果,我們按剛才第一個(gè)例子我所分析的過程來分析這段代碼,得到的是10;

故當(dāng)我們將#pragma pack的n值小于所有數(shù)據(jù)成員長(zhǎng)度的時(shí)候,結(jié)果將改變。

對(duì)齊的作用和原因

各個(gè)硬件平臺(tái)對(duì)存儲(chǔ)空間的處理上有很大的不同。如果不按照適合其平臺(tái)要求對(duì)數(shù)據(jù)存放進(jìn)行對(duì)齊,可能會(huì)在存取效率上帶來損失。

比如有些平臺(tái)每次讀都是從偶地址開始,如果一個(gè)int型在32位地址存放在偶地址開始的地方,那么一個(gè)讀周期就可以讀出;

而如果存放在其地址開始的地方,就可能會(huì)需要2個(gè)讀周期,并對(duì)兩次讀出的結(jié)果的高低字節(jié)進(jìn)行拼湊才能得到該int數(shù)據(jù)。那么在讀取效率上下降很多,這也是空間和時(shí)間的博弈。

CPU每次從內(nèi)存中取出數(shù)據(jù)或者指令時(shí),并非想象中的一個(gè)一個(gè)字節(jié)取出拼接的,而是根據(jù)自己的字長(zhǎng),也就是CPU一次能夠處理的數(shù)據(jù)長(zhǎng)度取出內(nèi)存塊。總之,CPU會(huì)以它“最舒服的”數(shù)據(jù)長(zhǎng)度來讀取內(nèi)存數(shù)據(jù)

舉個(gè)例子

如果有一個(gè)4字節(jié)長(zhǎng)度的指令準(zhǔn)備被讀取進(jìn)CPU處理,就會(huì)有兩種情況出現(xiàn):

4個(gè)字節(jié)起始地址剛好就在CPU讀取的地址處,這種情況下,CPU可以一次就把這個(gè)指令讀出,并執(zhí)行,內(nèi)存情況如下

面試常考,項(xiàng)目易錯(cuò),長(zhǎng)文詳解C/C++中的字節(jié)對(duì)齊

而當(dāng)4個(gè)字節(jié)按照如下圖所示分布時(shí)

面試??迹?xiàng)目易錯(cuò),長(zhǎng)文詳解C/C++中的字節(jié)對(duì)齊

假設(shè)CPU還在同一個(gè)地址取數(shù)據(jù),則取到第一個(gè)4字節(jié)單元得到了1、2字節(jié)的數(shù)據(jù),但是這個(gè)數(shù)據(jù)不符合需要的數(shù)字,所以CPU就要在后續(xù)的內(nèi)存中繼續(xù)取值,這才取到后面的4字節(jié)單元得到3、4字節(jié)數(shù)據(jù),從而和前面取到的1、2字節(jié)拼接成一個(gè)完整數(shù)據(jù)。

而本次操作進(jìn)行了兩次內(nèi)存讀取,考慮到CPU做大量的數(shù)據(jù)運(yùn)算和操作,如果遇到這種情況很多的話,將會(huì)嚴(yán)重影響CPU的處理速度。

因此,系統(tǒng)需要進(jìn)行內(nèi)存對(duì)齊,而這項(xiàng)任務(wù)就交給編譯器進(jìn)行相應(yīng)的地址分配和優(yōu)化,編譯器會(huì)根據(jù)提供參數(shù)或者目標(biāo)環(huán)境進(jìn)行相應(yīng)的內(nèi)存對(duì)齊。

什么時(shí)候需要進(jìn)行內(nèi)存對(duì)齊.

一般情況下都不需要對(duì)編譯器進(jìn)行的內(nèi)存對(duì)齊規(guī)則進(jìn)行修改,因?yàn)檫@樣會(huì)降低程序的性能,除非在以下兩種情況下:

這個(gè)結(jié)構(gòu)需要直接被寫入文件

這個(gè)結(jié)構(gòu)需通過網(wǎng)絡(luò)傳給其他程序

對(duì)齊的實(shí)現(xiàn)

可以通知給編譯器傳遞預(yù)編譯指令,從而改變對(duì)指定數(shù)據(jù)的對(duì)齊方法。

  1. unsigned int calc_align(unsigned int n,unsigned align)   
  2. {   
  3.     if ( n / align * align == n)             
  4.         return n;   
  5.     return  (n / align + 1) * align;   
  6. }  

不過這種算法的效率很低,下面介紹一種高效率的數(shù)據(jù)對(duì)齊算法:

  1. unsigned int calc_align(unsigned int n,unsigned align)   
  2. {       
  3.     return ((n + align - 1) & (~(align - 1)));   
  4. }   

這種算法的原理是:

(align-1) :對(duì)齊所需的對(duì)齊位,如:2字節(jié)對(duì)齊為1,4字節(jié)為11,8字節(jié)為111,16字節(jié)為1111...

(&~(align-1)) :將對(duì)齊位數(shù)據(jù)置位為0,其位為1

(n+(align-1)) & ~(align-1) :對(duì)齊后的數(shù)據(jù)

總結(jié)

通常,我們寫程序的時(shí)候,不需要考慮對(duì)齊問題,編譯器會(huì)替我們選擇目標(biāo)平臺(tái)的對(duì)齊策略。但正因?yàn)槲覀儧]注意這個(gè)問題,導(dǎo)致編輯器對(duì)數(shù)據(jù)存放做了對(duì)齊,而我們?nèi)绻涣私獾脑?,就?huì)對(duì)一些問題感到迷惑。所以知其然,更要知其所以然。好了,我們介紹到這里,下一期再見!

 

責(zé)任編輯:姜華 來源: 今日頭條
相關(guān)推薦

2024-01-18 10:27:30

C++引用函數(shù)

2023-11-09 23:56:21

2021-08-17 11:45:44

LinuxC語言字節(jié)

2011-07-15 01:10:13

C++內(nèi)存分配

2010-01-21 14:07:14

CC++聲明

2010-01-21 09:34:57

C++語法

2010-01-27 16:05:06

C++堆棧

2021-12-21 15:31:10

C++語言指針

2011-04-20 09:50:45

Virtual

2010-01-20 10:19:55

C++數(shù)組

2010-01-21 13:33:44

C++基類

2010-01-25 10:25:19

C++變量

2010-01-28 16:31:54

C++類型

2010-01-27 17:16:52

C++構(gòu)造函數(shù)

2020-08-21 13:20:36

C++If ElseLinux

2010-01-26 10:42:26

C++函數(shù)

2011-03-30 17:20:18

C++引用

2010-12-17 10:07:59

2010-02-06 16:30:25

C++內(nèi)存對(duì)齊

2010-01-26 14:35:11

C++關(guān)鍵字
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)