成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

聊聊Linux字節(jié)對(duì)齊的那些事

系統(tǒng) Linux
對(duì)齊跟數(shù)據(jù)在內(nèi)存中的位置有關(guān)。如果一個(gè)變量的內(nèi)存地址正好位于它長(zhǎng)度的整數(shù)倍,他就被稱做自然對(duì)齊。比如在32位cpu下,假設(shè)一個(gè)整型變量的地址為0x00000004,那它就是自然對(duì)齊的。

[[415839]]

最近一口君在做一個(gè)項(xiàng)目,遇到一個(gè)問(wèn)題,運(yùn)行于ARM上的threadx在與DSP通信采用消息隊(duì)列的方式傳遞消息(最終實(shí)現(xiàn)原理是中斷+共享內(nèi)存的方式),在實(shí)際操作過(guò)程中發(fā)現(xiàn)threadx總是crash,于是經(jīng)過(guò)排查,是因?yàn)閭鬟f消息的結(jié)構(gòu)體沒(méi)有考慮字節(jié)對(duì)齊的問(wèn)題。

隨手整理一下C語(yǔ)言中字節(jié)對(duì)齊的問(wèn)題與大家一起分享。

一、概念

對(duì)齊跟數(shù)據(jù)在內(nèi)存中的位置有關(guān)。如果一個(gè)變量的內(nèi)存地址正好位于它長(zhǎng)度的整數(shù)倍,他就被稱做自然對(duì)齊。比如在32位cpu下,假設(shè)一個(gè)整型變量的地址為0x00000004,那它就是自然對(duì)齊的。

首先了解什么位、字節(jié)、字

字長(zhǎng)

一個(gè)字的位數(shù),現(xiàn)代電腦的字長(zhǎng)通常為16,32, 64位。(一般N位系統(tǒng)的字長(zhǎng)是N/8字節(jié)。)

不同的CPU一次可以處理的數(shù)據(jù)位數(shù)是不同的,32位CPU可以一次處理32位數(shù)據(jù),64位CPU可以一次處理64位數(shù)據(jù),這里的位,指的就是字長(zhǎng)。

而所謂的字長(zhǎng),我們有時(shí)會(huì)稱為字(word)。在16位的CPU中,一個(gè)字剛好為兩個(gè)字節(jié),而32位CPU中,一個(gè)字是四個(gè)字節(jié)。若以字為單位,向上還有雙字(兩個(gè)字),四字(四個(gè)字)。

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

對(duì)于標(biāo)準(zhǔn)數(shù)據(jù)類型,它的地址只要是它的長(zhǎng)度的整數(shù)倍就行了,而非標(biāo)準(zhǔn)數(shù)據(jù)類型按下面的原則對(duì)齊:   數(shù)組 :按照基本數(shù)據(jù)類型對(duì)齊,第一個(gè)對(duì)齊了后面的自然也就對(duì)齊了。聯(lián)合 :按其包含的長(zhǎng)度最大的數(shù)據(jù)類型對(duì)齊。結(jié)構(gòu)體:結(jié)構(gòu)體中每個(gè)數(shù)據(jù)類型都要對(duì)齊。

三、如何限制定字節(jié)對(duì)齊位數(shù)?

1. 缺省

在缺省情況下,C編譯器為每一個(gè)變量或是數(shù)據(jù)單元按其自然對(duì)界條件分配空間。一般地,可以通過(guò)下面的方法來(lái)改變?nèi)笔〉膶?duì)界條件:

2. #pragma pack(n)

· 使用偽指令#pragma pack (n),C編譯器將按照n個(gè)字節(jié)對(duì)齊。· 使用偽指令#pragma pack (),取消自定義字節(jié)對(duì)齊方式。

#pragma pack(n) 用來(lái)設(shè)定變量以n字節(jié)對(duì)齊方式。n字節(jié)對(duì)齊就是說(shuō)變量存放的起始地址的偏移量有兩種情況:

  1. 如果n大于等于該變量所占用的字節(jié)數(shù),那么偏移量必須滿足默認(rèn)的對(duì)齊方式
  2. 如果n小于該變量的類型所占用的字節(jié)數(shù),那么偏移量為n的倍數(shù),不用滿足默認(rèn)的對(duì)齊方式。

結(jié)構(gòu)的總大小也有一個(gè)約束條件,如果n大于等于所有成員變量類型所占用的字節(jié)數(shù),那么結(jié)構(gòu)的總大小必須為占用空間最大的變量占用的空間數(shù)的倍數(shù);否則必須是n的倍數(shù)。

3. __attribute

另外,還有如下的一種方式:· __attribute((aligned (n))),讓所作用的結(jié)構(gòu)成員對(duì)齊在n字節(jié)自然邊界上。如果結(jié)構(gòu)中有成員的長(zhǎng)度大于n,則按照最大成員的長(zhǎng)度來(lái)對(duì)齊。· attribute ((packed)),取消結(jié)構(gòu)在編譯過(guò)程中的優(yōu)化對(duì)齊,按照實(shí)際占用字節(jié)數(shù)進(jìn)行對(duì)齊。

4. 匯編.align

匯編代碼通常用.align來(lái)制定字節(jié)對(duì)齊的位數(shù)。

.align:用來(lái)指定數(shù)據(jù)的對(duì)齊方式,格式如下:

  1. .align [absexpr1, absexpr2] 

以某種對(duì)齊方式,在未使用的存儲(chǔ)區(qū)域填充值. 第一個(gè)值表示對(duì)齊方式,4, 8,16或 32. 第二個(gè)表達(dá)式值表示填充的值。

四、為什么要對(duì)齊?

操作系統(tǒng)并非一個(gè)字節(jié)一個(gè)字節(jié)訪問(wèn)內(nèi)存,而是按2,4,8這樣的字長(zhǎng)來(lái)訪問(wèn)。因此,當(dāng)CPU從存儲(chǔ)器讀數(shù)據(jù)到寄存器,IO的數(shù)據(jù)長(zhǎng)度通常是字長(zhǎng)。如32位系統(tǒng)訪問(wèn)粒度是4字節(jié)(bytes), 64位系統(tǒng)的是8字節(jié)。當(dāng)被訪問(wèn)的數(shù)據(jù)長(zhǎng)度為n字節(jié)且該數(shù)據(jù)地址為n字節(jié)對(duì)齊時(shí),那么操作系統(tǒng)就可以高效地一次定位到數(shù)據(jù), 無(wú)需多次讀取,處理對(duì)齊運(yùn)算等額外操作。數(shù)據(jù)結(jié)構(gòu)應(yīng)該盡可能地在自然邊界上對(duì)齊。如果訪問(wèn)未對(duì)齊的內(nèi)存,CPU需要做兩次內(nèi)存訪問(wèn)。

字節(jié)對(duì)齊可能帶來(lái)的隱患:

代碼中關(guān)于對(duì)齊的隱患,很多是隱式的。比如在強(qiáng)制類型轉(zhuǎn)換的時(shí)候。例如:

  1. unsigned int i = 0x12345678; 
  2. unsigned char *p=NULL
  3. unsigned short *p1=NULL
  4.  
  5. p=&i; 
  6. *p=0x00; 
  7. p1=(unsigned short *)(p+1); 
  8. *p1=0x0000; 

最后兩句代碼,從奇數(shù)邊界去訪問(wèn)unsignedshort型變量,顯然不符合對(duì)齊的規(guī)定。在x86上,類似的操作只會(huì)影響效率,但是在MIPS或者sparc上,可能就是一個(gè)error,因?yàn)樗鼈円蟊仨氉止?jié)對(duì)齊.

五、舉例

例1:os基本數(shù)據(jù)類型占用的字節(jié)數(shù)

首先查看操作系統(tǒng)的位數(shù)

在64位操作系統(tǒng)下查看基本數(shù)據(jù)類型占用的字節(jié)數(shù):

  1. #include <stdio.h> 
  2.  
  3. int main() 
  4.     printf("sizeof(char) = %ld\n", sizeof(char)); 
  5.     printf("sizeof(int) = %ld\n", sizeof(int)); 
  6.     printf("sizeof(float) = %ld\n", sizeof(float)); 
  7.     printf("sizeof(long) = %ld\n", sizeof(long));                                       
  8.     printf("sizeof(long long) = %ld\n", sizeof(long long)); 
  9.     printf("sizeof(double) = %ld\n", sizeof(double)); 
  10.     return 0; 

例2:結(jié)構(gòu)體占用的內(nèi)存大小--默認(rèn)規(guī)則

考慮下面的結(jié)構(gòu)體占用的位數(shù)

  1. struct yikou_s 
  2.     double d; 
  3.     char c; 
  4.     int i; 
  5. } yikou_t; 

執(zhí)行結(jié)果

  1. sizeof(yikou_t) = 16 

在內(nèi)容中各變量位置關(guān)系如下:

其中成員C的位置還受字節(jié)序的影響,有的可能在位置8

編譯器給我們進(jìn)行了內(nèi)存對(duì)齊,各成員變量存放的起始地址相對(duì)于結(jié)構(gòu)的起始地址的偏移量必須為該變量類型所占用的字節(jié)數(shù)的倍數(shù), 且結(jié)構(gòu)的大小為該結(jié)構(gòu)中占用最大空間的類型所占用的字節(jié)數(shù)的倍數(shù)。

對(duì)于偏移量:變量type n起始地址相對(duì)于結(jié)構(gòu)體起始地址的偏移量必須為sizeof(type(n))的倍數(shù)結(jié)構(gòu)體大小:必須為成員最大類型字節(jié)的倍數(shù)

  1. char: 偏移量必須為sizeof(char) 即1的倍數(shù) 
  2. int: 偏移量必須為sizeof(int) 即4的倍數(shù) 
  3. float: 偏移量必須為sizeof(float) 即4的倍數(shù) 
  4. double: 偏移量必須為sizeof(double) 即8的倍數(shù) 

例3:調(diào)整結(jié)構(gòu)體大小

我們將結(jié)構(gòu)體中變量的位置做以下調(diào)整:

  1. struct yikou_s 
  2.     char c; 
  3.     double d; 
  4.     int i; 
  5. } yikou_t; 

執(zhí)行結(jié)果

  1. sizeof(yikou_t) = 24 

各變量在內(nèi)存中布局如下:

  • 當(dāng)結(jié)構(gòu)體中有嵌套符合成員時(shí),復(fù)合成員相對(duì)于結(jié)構(gòu)體首地址偏移量是復(fù)合成員最寬基本類型大小的整數(shù)倍。

例4:#pragma pack(4)

  1. #pragma pack(4) 
  2.  
  3. struct yikou_s 
  4.     char c; 
  5.     double d; 
  6.     int i; 
  7. } yikou_t; 
  1. sizeof(yikou_t) = 16 

例5:#pragma pack(8)

  1. #pragma pack(8) 
  2.  
  3. struct yikou_s 
  4.     char c; 
  5.     double d; 
  6.     int i; 
  7. } yikou_t; 
  1. sizeof(yikou_t) = 24 

例6:匯編代碼

舉例:以下是截取的uboot代碼中異常向量irq、fiq的入口位置代碼:

六、匯總實(shí)力

有手懶的同學(xué),直接貼一個(gè)完整的例子給你們:

  1. #include <stdio.h> 
  2. main() 
  3. struct A { 
  4.     int a; 
  5.     char b; 
  6.     short c; 
  7. }; 
  8.   
  9. struct B { 
  10.     char b; 
  11.     int a; 
  12.     short c; 
  13. }; 
  14. struct AA { 
  15.    // int a; 
  16.     char b; 
  17.     short c; 
  18. }; 
  19.  
  20. struct BB { 
  21.     char b; 
  22.    // int a; 
  23.     short c; 
  24. };  
  25. #pragma pack (2) /*指定按2字節(jié)對(duì)齊*/ 
  26. struct C { 
  27.     char b; 
  28.     int a; 
  29.     short c; 
  30. }; 
  31. #pragma pack () /*取消指定對(duì)齊,恢復(fù)缺省對(duì)齊*/ 
  32.   
  33.   
  34.   
  35. #pragma pack (1) /*指定按1字節(jié)對(duì)齊*/ 
  36. struct D { 
  37.     char b; 
  38.     int a; 
  39.     short c; 
  40. }; 
  41. #pragma pack ()/*取消指定對(duì)齊,恢復(fù)缺省對(duì)齊*/ 
  42.   
  43. int s1=sizeof(struct A); 
  44. int s2=sizeof(struct AA); 
  45. int s3=sizeof(struct B); 
  46. int s4=sizeof(struct BB); 
  47. int s5=sizeof(struct C); 
  48. int s6=sizeof(struct D); 
  49. printf("%d\n",s1); 
  50. printf("%d\n",s2); 
  51. printf("%d\n",s3); 
  52. printf("%d\n",s4); 
  53. printf("%d\n",s5); 
  54. printf("%d\n",s6); 

本文轉(zhuǎn)載自微信公眾號(hào)「一口Linux」,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系一口Linux公眾號(hào)。

 

責(zé)任編輯:姜華 來(lái)源: 一口Linux
相關(guān)推薦

2021-08-30 12:05:46

Linux字節(jié)對(duì)齊代碼

2021-08-17 11:45:44

LinuxC語(yǔ)言字節(jié)

2023-07-31 08:21:22

語(yǔ)法校對(duì)器Pick

2020-11-30 13:10:39

MySQL安全服務(wù)器

2022-09-09 08:08:28

開(kāi)源項(xiàng)目服務(wù)

2017-05-15 21:50:54

Linux引號(hào)

2019-01-07 12:02:02

TCP長(zhǎng)連接Java

2024-02-21 07:24:21

微服務(wù)單體架構(gòu)MVC

2017-12-21 08:06:40

2018-04-11 08:54:16

Linux ARM存儲(chǔ)分布

2020-10-30 07:43:35

Jenkins配置前端

2022-02-15 19:50:18

加載器JAVAJDK

2024-10-14 12:34:08

2021-10-26 11:42:51

系統(tǒng)

2020-05-09 12:16:12

中臺(tái)架構(gòu)工具

2014-07-22 10:42:04

2014-06-06 16:08:17

初志科技

2011-09-19 15:40:35

2020-07-29 08:14:59

云計(jì)算云遷移IT

2017-11-20 09:00:34

Linux服務(wù)器時(shí)間同步
點(diǎn)贊
收藏

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

主站蜘蛛池模板: 国产情侣激情 | 久久久久亚洲精品 | 国产综合视频 | 69精品久久久久久 | 99精品国产一区二区青青牛奶 | www久久久 | 麻豆天堂| 欧美日韩久久 | 免费观看一区二区三区毛片 | 成在线人视频免费视频 | xxxxx免费视频 | 国产91一区二区三区 | 国产视频精品在线 | 日日艹夜夜艹 | 欧美一区2区三区4区公司二百 | 久久精品一区 | 色视频在线播放 | 欧美精品中文 | h肉视频 | 日韩在线一区二区三区 | 亚洲一级淫片 | 一级黄色日本片 | 99久久婷婷国产综合精品 | 国产一区91精品张津瑜 | 日韩精品一区二区三区中文字幕 | 欧美亚洲一区二区三区 | 国产成人精品久久二区二区 | 麻豆久久久9性大片 | 91亚洲国产 | 97色在线视频 | 一区二区三区在线播放视频 | 超碰美女在线 | 久久99国产精一区二区三区 | 91美女在线观看 | 久草资源在线视频 | 91一区二区在线观看 | 西西裸体做爰视频 | 成人小视频在线观看 | a级黄色毛片免费播放视频 国产精品视频在线观看 | 伊人狠狠 | 成人福利在线 |