日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

顶级C程序员之路

發(fā)布時(shí)間:2024/4/11 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 顶级C程序员之路 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

?hi,大家好,我是極客君,今天分享一篇幾年前在CSDN上發(fā)表的文章。C語(yǔ)言是我非常喜歡的語(yǔ)言,也是眾多高級(jí)語(yǔ)言的鼻祖。

C語(yǔ)言的優(yōu)勢(shì):

門檻低:核心特性和標(biāo)準(zhǔn)庫(kù)都比較簡(jiǎn)單;

上限高:語(yǔ)法精簡(jiǎn),編程自由度高,可以玩出各種高端操作;

性能強(qiáng):極少抽象, 幾乎完全對(duì)應(yīng)到匯編實(shí)現(xiàn),性能強(qiáng),首選底層系統(tǒng)開發(fā)語(yǔ)言。

TIOBE編程社區(qū)揭曉了各大編程語(yǔ)言的排行情況:

Google搜索排行榜:

知乎熱門討論:

大量重量級(jí)軟件都是C寫的,比如Linux,UNIX,IOS內(nèi)核,windows內(nèi)核,Android內(nèi)核,jvm虛擬機(jī),CPython,Nginx,Redis,MySQL,GCC,GDB等等,可以看到,整個(gè)世界的基礎(chǔ)架構(gòu)都是在 C 語(yǔ)言之上運(yùn)行的,C語(yǔ)言是你必須學(xué)習(xí)的語(yǔ)言。因?yàn)檫@個(gè)世界上絕大多數(shù)編程語(yǔ)言都是 C-like 的語(yǔ)言,也是在不同的方面來(lái)解決 C 語(yǔ)言的各種問(wèn)題。學(xué)習(xí) C 語(yǔ)言是一個(gè)合格的程序員的必經(jīng)之路。

下面章節(jié)進(jìn)入今天的主題

深入理解字節(jié),字節(jié)序與字節(jié)對(duì)齊?

? ? ??? ? ? ? ? ? ? ? ?

一 總述

??

作為一個(gè)職業(yè)的coder玩家,首先應(yīng)該對(duì)計(jì)算機(jī)的字節(jié)有所了解。我們經(jīng)常談到的2進(jìn)制流,字節(jié)(字符)流,數(shù)據(jù)類型流(針對(duì)編程),結(jié)構(gòu)流等說(shuō)法,2進(jìn)制流,0和1的操作,屬于cpu級(jí),從字符流向上都是我們玩家關(guān)心,字節(jié)流屬于操作系統(tǒng)級(jí),今天談的就是字節(jié)流操作。

二? 字節(jié)

???

因?yàn)橛?jì)算機(jī)用二進(jìn)制,所以希望基本存儲(chǔ)單位的是2的n次方(和硬件設(shè)計(jì)有關(guān))。這樣讀取字節(jié)的時(shí)候,開銷不會(huì)太高,可以達(dá)到最大性能,因?yàn)閯傞_始,計(jì)算機(jī)是美國(guó)發(fā)明的,西文字符(英文字母大小寫,數(shù)字,其他特殊字符等將近有1百多個(gè),所以用7位來(lái)表示,這樣可以把所有西文字符表達(dá)完,再加上一位校檢位,一共8位,由于ASCⅡ的廣泛應(yīng)用,所有后來(lái),一個(gè)字節(jié)占8位就成了國(guó)際規(guī)定的標(biāo)準(zhǔn)了,一直沿用至今(有待研究,但不是今天的主題)。

???

一個(gè)字節(jié)占8個(gè)2進(jìn)制位,數(shù)據(jù)類型流,就是在c語(yǔ)言里面的數(shù)據(jù)類型占多少個(gè)字節(jié)。然后直接操作數(shù)據(jù)類型。在目前的32位系統(tǒng)中,c語(yǔ)言的基本數(shù)據(jù)類型有以下幾種:

Char??占一個(gè)字節(jié)?(-2^7?-?2^7-1?,-128?到?127)最高位?為符號(hào)位

Unsigned?char?占一個(gè)字節(jié)???(0-2^8,0到255)

Short???占2個(gè)字節(jié)?(-2^15?-?2^15-1?,?-32768到32767)最高位?為符號(hào)位

Unsigned?short?占2個(gè)字節(jié)?(0?-?2^16?,?0到65536)

Int?(字長(zhǎng),對(duì)于32位機(jī)為32位,16位機(jī)為16位,長(zhǎng)度不固定,和系統(tǒng)平臺(tái)有關(guān),處理器位數(shù)有關(guān),代表尋址空間),在32位機(jī)占4個(gè)字節(jié)(-2^31-2^31?)最高位?為符號(hào)位

Unsigned??int?占4個(gè)字節(jié)(0-2^32?)

Long?int?為4個(gè)字節(jié),在16,32位機(jī)都占4個(gè)字節(jié)(-2^31-2^31?)最高位?為符號(hào)位

Unsigned??long?int占4個(gè)字節(jié)(0-2^32?)

sizeof(short)?<=?sizeof(int)?<=?sizeof(long)??

在32位機(jī) int和long都是32位,沒(méi)有什么大的區(qū)別,但還是有些小的區(qū)別,有時(shí)最好用long,他大小固定,如果到其他平臺(tái),比如64位,他還是占4個(gè)字節(jié),而int卻占8個(gè)字節(jié),可以增加代碼的可移植性。

Long?long?int?占8個(gè)字節(jié)(c99標(biāo)準(zhǔn))??

Unsigned?long?long?int?占8個(gè)字節(jié)(c99標(biāo)準(zhǔn))??

浮點(diǎn)類型?由于浮點(diǎn)類型和整形的編碼不一樣,所以浮點(diǎn)型需要特殊分析。

Float?占4個(gè)字節(jié) ?

Double?占8個(gè)字節(jié)?

三 字節(jié)序

為什么有字節(jié)序這個(gè)概念存在呢?

不同的CPU有不同的字節(jié)序類型,這些字節(jié)序是指整數(shù)在內(nèi)存中保存的順序?這個(gè)叫做主機(jī)序 ,就是多個(gè)字節(jié)在內(nèi)存中擺放位置順序和解釋順序。

最常見(jiàn)的有兩種?:

1. Little endian:將低序字節(jié)存儲(chǔ)在起始地址? 4321

2. Big endian:將高序字節(jié)存儲(chǔ)在起始地址??? 1234

LE?little-endian?

最符合人的思維的字節(jié)序,地址低位存儲(chǔ)值的低位 ,地址高位存儲(chǔ)值的高位,怎么講是最符合人的思維的字節(jié)序,是因?yàn)閺娜说牡谝挥^感來(lái)說(shuō)低位值小,就應(yīng)該放在內(nèi)存地址小的地方,也即內(nèi)存地址低位,反之,高位值就應(yīng)該放在內(nèi)存地址大的地方,也即內(nèi)存地址高位。

BE?big-endian?

最直觀的字節(jié)序,地址低位存儲(chǔ)值的高位 ,地址高位存儲(chǔ)值的低位,為什么說(shuō)直觀,不要考慮對(duì)應(yīng)關(guān)系,只需要把內(nèi)存地址從左到右按照由低到高的順序?qū)懗?#xff0c;把值按照通常的高位到低位的順序?qū)懗鰞烧邔?duì)照,一個(gè)字節(jié)一個(gè)字節(jié)的填充進(jìn)去 。

例子:如果我們將0x1234abcd寫入到以0x0000開始的內(nèi)存中,則結(jié)果為
內(nèi)存地址? ? ? ? big-endian???little-endian

0x0000? ? ? ????0x12?????? ? ? ? ??0xcd
0x0001? ? ? ? ? 0x34? ? ? ? ? ? ? ?0xab
0x0002? ? ? ? ??0xab? ? ? ? ? ? ?? 0x34
0x0003? ? ? ? ? 0xcd? ? ? ? ? ? ? ?0x12

網(wǎng)絡(luò)字節(jié)序

網(wǎng)絡(luò)字節(jié)序是TCP/IP協(xié)議棧中規(guī)定好的一種數(shù)據(jù)表示格式,它與具體的CPU類型、操作系統(tǒng)等無(wú)關(guān),從而可以保證數(shù)據(jù)在不同主機(jī)之間傳輸時(shí)能夠被正確解釋。網(wǎng)絡(luò)字節(jié)順序采用big endian排序方式。

為了進(jìn)行轉(zhuǎn)換 bsd socket提供了轉(zhuǎn)換的函數(shù)?有下面四個(gè):

linux的源代碼(/include/netinet/in.h)

#?if?__BYTE_ORDER?==?__BIG_ENDIAN?
/*?The?host?byte?order?is?the?same?as?network?byte?order,?
???so?these?functions?are?all?just?identity.??*/?
#?define?ntohl(x)?(x)?
#?define?ntohs(x)?(x)?
#?define?htonl(x)?(x)?
#?define?htons(x)?(x)?
#?else?
#??if?__BYTE_ORDER?==?__LITTLE_ENDIAN?
#???define?ntohl(x)?__bswap_32?(x)?
#???define?ntohs(x)?__bswap_16?(x)?
#???define?htonl(x)?__bswap_32?(x)?
#???define?htons(x)?__bswap_16?(x)?
#??endif?
#?endif


htons?把unsigned?short類型從主機(jī)序轉(zhuǎn)換到網(wǎng)絡(luò)序
htonl?把unsigned?long類型從主機(jī)序轉(zhuǎn)換到網(wǎng)絡(luò)序
ntohs?把unsigned?short類型從網(wǎng)絡(luò)序轉(zhuǎn)換到主機(jī)序
ntohl?把unsigned?long類型從網(wǎng)絡(luò)序轉(zhuǎn)換到主機(jī)序

在使用little endian的系統(tǒng)中這些函數(shù)會(huì)把字節(jié)序進(jìn)行轉(zhuǎn)換, 在使用big endian類型的系統(tǒng)中這些函數(shù)會(huì)定義成空,什么都不做。

htonl(x)我簡(jiǎn)化為下:

?#define??htonl(x)??\??//連接符,連接下一行

??((unsigned?long?)?\

(?\

(((unsigned?long)(x)&0x000000ff<<24)|?\

(((unsigned?long)(x)&0x0000ff00)<<8)|?\

(((unsigned?long)(x)&0x00ff0000)>>8)|?\

(((unsigned?long)(x)&0xff000000)>>24)\

))

一般c語(yǔ)言編寫程序的字節(jié)序都是系統(tǒng)相關(guān)的,叫主機(jī)序,即指系統(tǒng)處理器本身所采用的字節(jié)序,java的字節(jié)碼是big-endian 和網(wǎng)絡(luò)字節(jié)序一樣,所以他和網(wǎng)絡(luò)通信不需要關(guān)心字節(jié)序問(wèn)題,如果要和其他平臺(tái)進(jìn)行通信,都要進(jìn)行字節(jié)序轉(zhuǎn)換,一般采用標(biāo)準(zhǔn)化的網(wǎng)絡(luò)序進(jìn)行傳輸:

發(fā)送端:主機(jī)序->網(wǎng)絡(luò)序

接收端:?網(wǎng)絡(luò)序->主機(jī)序

不管哪種字節(jié)序,目的都是大家對(duì)01二進(jìn)制串解釋都一樣,?不然兩方的解釋不一樣就可能會(huì)產(chǎn)生嚴(yán)重的問(wèn)題。

對(duì)于IP頭定義里面ihl和version字段需要考慮主機(jī)字節(jié)序;__be 表示big endian

網(wǎng)絡(luò)上流傳一個(gè)測(cè)試自己系統(tǒng)是什么字節(jié)序函數(shù)代碼:

byte_type get_sys_byte_order()

{

?? ? union? {

?? ? ? ? int ?b;

?? ? ? ? char a[4];

?? ? }U;

?? ? U.b = 0x01;

?? ? if(0x01 == U.a[0] )?{

?? ? ? ? return ? little_endian_type;

?? ? ?}else?{

?? ? ? ? return ? big_endian_type;

?? ? ?}?
}?

注:不同的CPU上運(yùn)行不同的操作系統(tǒng),字節(jié)序也是不同的,參見(jiàn)下表:

處理器?

? 操作系統(tǒng)

?字節(jié)序

Alpha? ? ? ? ? ??

全部

?Little?endian

ARM

全部

?Little?endian

Intelx86

全部? ? ?

?Little?endian?

AMD

全部? ? ?

?Little?endian

MIPS? ? ? ? ? ? ??

NT? ?

?Little?endian

MIPS? ? ? ? ? ? ?

UNIX? ? ?

?Big?endian?

PowerPC? ? ? ? ? ?

NT? ? ??

?Little?endian

PowerPC? ? ? ? ??

非NT??? ?

?Big?endian?

x86,AMD,ARM等芯片平臺(tái)是小端字節(jié)序系統(tǒng)

PowerPC?,PPC等芯片平臺(tái)是大端字節(jié)序系統(tǒng)

為什么不統(tǒng)一字節(jié)序?

1. 計(jì)算都是從低位開始的,因此計(jì)算機(jī)內(nèi)部處理采用小端序,效率較高。

2. 對(duì)于大端序,由于符號(hào)位在高位,因此對(duì)于數(shù)據(jù)正負(fù)或大小的判斷也就方便許多;其次,大端序也更符合人類的閱讀習(xí)慣。

3. 由于大小端各有優(yōu)劣,各個(gè)芯片廠商的堅(jiān)持自己設(shè)計(jì),字節(jié)序的問(wèn)題也就一直沒(méi)有統(tǒng)一。

字節(jié)序總結(jié)

  • 不同處理器之間采用的字節(jié)序可能不同。

  • 有些處理器的字節(jié)序是確定的,有些處理器的字節(jié)序是可配置的。

  • 網(wǎng)絡(luò)序一般統(tǒng)一為大端序。

  • 數(shù)據(jù)從本地傳輸?shù)骄W(wǎng)絡(luò),需要轉(zhuǎn)換為網(wǎng)絡(luò)序,接收到的網(wǎng)絡(luò)數(shù)據(jù)需要轉(zhuǎn)換為本地序后使用。

  • C提供了一組接口用于整型數(shù)據(jù)在本地序和網(wǎng)絡(luò)序之間的轉(zhuǎn)換。

  • 多字節(jié)數(shù)據(jù)對(duì)象才需要轉(zhuǎn)字節(jié)序,例如int,short等,而char不需要。

  • 由于處理器是按照IEEE標(biāo)準(zhǔn)處理float和double的,因此也不需要轉(zhuǎn)字節(jié)序。

  • 由于Java虛擬機(jī)的存在,Java不需要考慮大小端的問(wèn)題。

四 字節(jié)對(duì)齊

首先我看哈程序的優(yōu)化種類:

Cpu級(jí)優(yōu)化((讀內(nèi)存),流水線,cache,現(xiàn)在多核等)->2進(jìn)制級(jí)(即01代碼)優(yōu)化(現(xiàn)在估計(jì)沒(méi)有人去做了)->匯編級(jí)(指令)優(yōu)化->高級(jí)程序里面的代碼級(jí)優(yōu)化(位運(yùn)算,前++和后++,數(shù)組和指針,if?else和switch?case等優(yōu)化)->算法優(yōu)化(流程優(yōu)化)->軟件架構(gòu)級(jí)優(yōu)化......

而現(xiàn)在我們討論的字節(jié)對(duì)齊屬于cpu級(jí)優(yōu)化,可以加速cpu讀取內(nèi)存時(shí)間。

什么是字節(jié)對(duì)齊?

現(xiàn)代計(jì)算機(jī)中內(nèi)存空間都是按照byte劃分的,從理論上講似乎對(duì)任何類型的變量的訪問(wèn)可以從任何地址開始,但實(shí)際情況是在訪問(wèn)特定類型變量的時(shí)候經(jīng)常在特定的內(nèi)存地址訪問(wèn),這就需要各種類型數(shù)據(jù)按照一定的規(guī)則在空間上排列,而不是順序的一個(gè)接一個(gè)的排放,這就是對(duì)齊。?

為什么要字節(jié)對(duì)齊

原因一: CPU讀取內(nèi)存效率

各個(gè)硬件平臺(tái)對(duì)存儲(chǔ)空間的處理上有很大的不同。一些平臺(tái)對(duì)某些特定類型的數(shù)據(jù)只能從某些特定地址開始存取。

比如有些架構(gòu)的CPU在訪問(wèn)一個(gè)沒(méi)有進(jìn)行對(duì)齊的變量的時(shí)候會(huì)發(fā)生錯(cuò)誤(比如高通平臺(tái),一般的手機(jī)平臺(tái)都采用美國(guó)高通公司開發(fā)平臺(tái),對(duì)于無(wú)線上網(wǎng)卡來(lái)說(shuō),現(xiàn)在都是多核,要么是arm9+arm11,要么是arm9+2個(gè)Qdsp(Q是表示高通的dsp處理器)等處理器架構(gòu),然而在Qdsp中,如果訪問(wèn)了非對(duì)齊的內(nèi)存,就會(huì)直接發(fā)生錯(cuò)誤,直接把系統(tǒng)crush掉)那么在這種架構(gòu)下編程必須保證字節(jié)對(duì)齊。

其他平臺(tái)可能沒(méi)有這種情況,但是最常見(jiàn)的是如果不按照適合其平臺(tái)要求對(duì)數(shù)據(jù)存放進(jìn)行對(duì)齊,會(huì)在存取效率上帶來(lái)?yè)p失。比如有些平臺(tái)每次讀都是從偶地址開始,如果一個(gè)int型(假設(shè)為32位系統(tǒng))如果存放在偶地址開始的地方,那么一個(gè)讀周期就可以讀出這32bit。

而如果存放在奇地址開始的地方,就需要2個(gè)讀周期,并對(duì)兩次讀出的結(jié)果的高低字節(jié)進(jìn)行拼湊才能得到該32bit數(shù)據(jù)。顯然在讀取效率上下降很多。?

原因二 : Cache親和性

結(jié)構(gòu)的數(shù)據(jù)跨越兩個(gè)cache line,就意味著兩次load或者兩次store。如果數(shù)據(jù)結(jié)構(gòu)是cache line對(duì)齊的,? 就有可能減少一次讀寫。

掌握字節(jié)對(duì)齊的估算方法

學(xué)會(huì)估算結(jié)構(gòu)大小,可以幫助我們更好地設(shè)計(jì)程序的數(shù)據(jù)結(jié)構(gòu),比如合理地節(jié)約內(nèi)存,提供數(shù)據(jù)訪問(wèn)效率等。

1. 對(duì)于基本數(shù)據(jù)類型對(duì)齊要求:

Char 類型一個(gè)字節(jié)對(duì)齊,可以從任何內(nèi)存地址讀取;

Short2個(gè)字節(jié),要求是從偶內(nèi)存地址讀取;

Int 4個(gè)字節(jié)(32位系統(tǒng)),要求是變量的內(nèi)存地址必須被4整除;

Long和int一樣(在32位系統(tǒng)中)

Double 8個(gè)字節(jié),要求是變量的內(nèi)存地址必須被8整除。

2. 對(duì)于struct和union對(duì)齊要求是:

在c語(yǔ)言中存在struct和union結(jié)構(gòu)體類型,屬于復(fù)雜類型,成員中自身對(duì)齊值最大的那個(gè)值?。

注:結(jié)構(gòu)的總大小為結(jié)構(gòu)的字節(jié)邊界數(shù)(即該結(jié)構(gòu)中占用最大空間的變量的類型所占用的字節(jié)數(shù))的倍數(shù), 對(duì)于結(jié)構(gòu)體最終大小,還要參考,指定對(duì)齊值n。

以下部分屬于具體計(jì)算方法(有很多公式,但這些公式你可能從來(lái)沒(méi)有看到過(guò)),不想看可以跳過(guò)這一節(jié)。

struct

s表示結(jié)構(gòu)體,假使結(jié)構(gòu)體有m個(gè)成員,?定義A(x)表示第x個(gè)成員的對(duì)齊值, X(i)表示其第i個(gè)成員(按順序從上往下)所占的大小,?H(x)表示前面x個(gè)成員最終占內(nèi)存大小, 則結(jié)構(gòu)體的大小可以通過(guò)下面公式估算出來(lái):

初始值--基本類型type對(duì)齊值:

??A(char)?=?1;

??A(short)?=?2;

??A(int)?=?4;

??A(long)?=?4;

??A(float)?=?4;

??A(double)?=?8;

基本類型成員對(duì)齊值,type為基本類型成員x對(duì)應(yīng)的基本類型:

第x個(gè)成員對(duì)齊值:

A(x) = min(A(type),n );????公式1

整個(gè)結(jié)構(gòu)對(duì)齊值:

A(s)?= min(max(A(1),A(2),...,A(m)),n)????公式2

則struct結(jié)構(gòu)體前x+1個(gè)成員和前x成員之間計(jì)算公式:

If(H(x)%A(x+1)?==?0)

??H(x+1)=?H(x)+X(x+1);

Else

??H(x+1)=?H(x)+A(x+1)-H(x)%A(x+1)+X(x+1);?

其中?H(1)?= X(1),A(1)=?X(1);???公式3

則結(jié)構(gòu)體最終結(jié)構(gòu)體大小X(s)為:

If(H(m)%A(s)?==?0)

???X(s) =?H(m);

Else

???X(s) =?H(m)+A(s)-H(m)%A(s);??公式4?

union

U表示這個(gè)結(jié)構(gòu)體,X(i)表示其第i個(gè)成員(按順序從上往下)所占的大小;假使結(jié)構(gòu)體有m個(gè)成員;結(jié)構(gòu)體的最終對(duì)齊值??

A(u)?=?min(max(A(1),A(2),...,A(m)),n)?公式5

定義H(x)表示前面x個(gè)成員實(shí)際占內(nèi)存大小;A(x)表示第x個(gè)成員的對(duì)齊值,可以有公式1給出,?Union結(jié)構(gòu)體最終占內(nèi)存大小為X(u),?則:

則union結(jié)構(gòu)體前x+1個(gè)成員和前x成員之間計(jì)算公式:

H(x+1)=?max(X(x+1),?H(x));

其中?H(1)?=?X(1);???公式6

則最終union結(jié)構(gòu)體大小X(u)為:

If(H(m)%A(u)?==?0)

???X(u) =?H(m);

Else

???X(u)?=?H(m)+A(u)-H(m)%A(u);??公式7?

公式4和公式7一般實(shí)現(xiàn):

指定對(duì)齊值

VC/VS編譯器

如果我們想指定對(duì)齊值,可以在VC IDE中,可以這樣修改:[Project]|[Settings],c/c++選項(xiàng)卡Category的Code Generation選項(xiàng)的Struct Member Alignment中修改,默認(rèn)是8字節(jié),針對(duì)全部變量,如果想動(dòng)態(tài)改變部分,在vc中可以用宏命令?

#pragma pack (n)時(shí)的指定對(duì)齊值n

#pragma pack()取消,之間的數(shù)據(jù)都是指定為n,但不一定為對(duì)齊n。

最終的數(shù)據(jù)成員對(duì)齊值為:?自身對(duì)齊值和指定對(duì)齊值中小的那個(gè)值。

GCC編譯器

__attribute__((aligned(n)))?表示所定義的變量為n字節(jié)對(duì)齊。

__attribute__((__packed__))? 表示結(jié)構(gòu)體內(nèi)不填充多余的字節(jié),一般用于通信協(xié)議結(jié)構(gòu)體定義;

__attribute__((__aligned__(SMP_CACHE_BYTES)))表示結(jié)構(gòu)按cache對(duì)齊,提高數(shù)據(jù)訪問(wèn)效率。

結(jié)構(gòu)中帶有結(jié)構(gòu)

不必考慮整個(gè)子結(jié)構(gòu),只考慮子結(jié)構(gòu)的基本類型并參照前面的規(guī)則來(lái)分配空間。空結(jié)構(gòu)(即不帶任何的方法和數(shù)據(jù))占用的1字節(jié)的空間。

枚舉中(enum)?
枚舉始終占用4字節(jié)的空間。

結(jié)構(gòu)中成員

結(jié)構(gòu)的靜態(tài)成員不對(duì)結(jié)構(gòu)的大小產(chǎn)生影響,因?yàn)殪o態(tài)變量的存儲(chǔ)位置與結(jié)構(gòu)的實(shí)例地址無(wú)關(guān),要理解上面的對(duì)齊規(guī)則,最好是分析一些典型的對(duì)齊例子:

例子1:

struct?MyStruct?{?
??char?dda;?
??double?dda1;?
??int?type?

};?

默認(rèn)指定對(duì)齊值n = 8(vc),其他自己查看,則n = 8;

由公式1?得到此結(jié)構(gòu)體的最終對(duì)齊值為?A(s)?=?8

有上面公式2?,3?可以得到?X(MyStruct)(=sizeof(MyStruct))?:

H(1)?=?1,?H(2)?=(H(1))?1+7+8?=?16;?H(3)?=(H(2))?16+4?=?20;

X(s)?=?(H(3))20?+?(A(s)-H(3)%A(s))?4?=?24;

所以sizeof(MyStruct)?= 24;

例子2:

#pragma??pack(2)

struct?MyStruct?{?
??char?dda;???A(1)?=?1?
??double?dda1;?A(2)?=?2?
? int type ;? A(3)?= 2
};?

#pragma??pack()

由公式1,2得到此結(jié)構(gòu)體的最終對(duì)齊值為?A(s)?=?2

有上面公式3?,4?可以得到?X(MyStruct)(sizeof(MyStruct))?:

H(1)?= 1, H(2)?=(H(1)) 1+?(A(2)-H(1)%A(2)) 1+(X2)8 = 10;?因?yàn)镠(2)%A(3)==0;

所以?H(3)?=(H(2))?10+4?=?14;

因?yàn)镠(3)%A(s)?==?0;

所以X(s)?=?(H(3))?14;

所以sizeof(MyStruct)?= 14;

例子3:

這里有個(gè)結(jié)構(gòu)體嵌套例子,對(duì)于結(jié)構(gòu)體中的結(jié)構(gòu)體成員,不要認(rèn)為它的對(duì)齊方式就是他的大小,看下面的例子:

struct?s1{
char?a[8];?
};
struct?s2{
double?d;?
};
struct?s3{
s1?s;?
char?a;?
};
struct?s4{
s2?s;?
char?a;?
};
默認(rèn)指定對(duì)齊值n = 8;

A(s1)?= 1;A(s2)?=min(min(A(double), 8),8)?=8 ;?

A(s3)?=?min(max(A(x1)=min(A(s1)?=?1,8)?=?1,A(x2)?=?1),8)?=?1;

A(s4)?=?min(max(A(x1)=min(A(s2)?=?8,8)?=?8,A(x2)?=?1),8)?=?8;

X(s1)?=?8;

X(s2)?=?8;

X(s3)?=?9;

X(s4)?=?16;

以上只是一些測(cè)試?yán)?#xff0c;真實(shí)的結(jié)構(gòu)體都比較龐大,一般用sizeof就可以了,但心里要清楚,每個(gè)成員的偏移量和填充的字節(jié),這些都可以由上面的公式推出來(lái)(平時(shí)最應(yīng)該注意的),我這里就暫時(shí)不推導(dǎo)了。

字節(jié)對(duì)齊利弊

1. 對(duì)齊意味著可能有內(nèi)存浪費(fèi)(特別是數(shù)組這樣連續(xù)分配的數(shù)據(jù)結(jié)構(gòu)),所以需要在空間和時(shí)間兩方面權(quán)衡。

2. 跨平臺(tái)通信場(chǎng)景,每個(gè)平臺(tái)程序字節(jié)對(duì)齊不一樣,可能會(huì)導(dǎo)致內(nèi)存空間解析出錯(cuò),所以一般采用1字節(jié)對(duì)齊,中間不含填充數(shù)據(jù),但這樣會(huì)導(dǎo)致一些屬性訪問(wèn)性能下降,需要綜合考慮。

字節(jié)對(duì)齊總結(jié)

  • 結(jié)構(gòu)體成員合理安排位置,節(jié)省空間,提高性能

  • 跨平臺(tái)數(shù)據(jù)結(jié)構(gòu)可考慮1字節(jié)對(duì)齊,節(jié)省空間,解析安全,影響訪問(wèn)效率

  • 跨平臺(tái)數(shù)據(jù)結(jié)構(gòu)進(jìn)行結(jié)構(gòu)優(yōu)化(對(duì)齊填充),提高訪問(wèn)效率,解析風(fēng)險(xiǎn),不節(jié)省空間

  • 本地?cái)?shù)據(jù)采用chace對(duì)齊,提高訪問(wèn)效率

  • 32位與64位默認(rèn)對(duì)齊數(shù)不一樣

五 最后總結(jié)

?

對(duì)于字節(jié)的理解,其實(shí)這些還不夠,掌握這些只是作為頂級(jí)c程序員最基本的要求(路還很長(zhǎng)),細(xì)節(jié)需要參考一下cpu的手冊(cè)。

其實(shí)在實(shí)際編程當(dāng)中,出現(xiàn)字節(jié)對(duì)齊的原因是通信的要求,如果是通過(guò)tcp/ip(互聯(lián)網(wǎng))通信,這樣一般協(xié)議頭部都是一個(gè)字節(jié)對(duì)齊,這樣對(duì)方解釋的時(shí)候是只需按協(xié)議解析就正確了;

或者是動(dòng)態(tài)庫(kù)調(diào)用,給別人的接口函數(shù)對(duì)應(yīng)參數(shù),如果是沒(méi)有滿足字節(jié)對(duì)齊的要求(不相同),如果進(jìn)行強(qiáng)制類型轉(zhuǎn)換或者按偏移量訪問(wèn)變量,就有可能出現(xiàn)錯(cuò)誤(某些嵌入式cpu)或者意想不到問(wèn)題,所以對(duì)于嵌入式開發(fā)的程序員最好是心里有數(shù)。

??

最后,讓我們來(lái)設(shè)計(jì)一個(gè)memcpy函數(shù),為什么要設(shè)計(jì)這個(gè)函數(shù)呢,如果你看過(guò)很多大型工程代碼,你就明白了,這個(gè)函數(shù)使用率相當(dāng)高,strcpy這個(gè)的優(yōu)化版本內(nèi)部都是調(diào)用memcpy來(lái)完成,這是系統(tǒng)函數(shù),每個(gè)平臺(tái)自己都實(shí)現(xiàn)了這個(gè)函數(shù),而且里面充滿很多編程技巧,看看自己會(huì)長(zhǎng)見(jiàn)識(shí)。

參考:
高通芯片平臺(tái)的memcpy函數(shù):

技術(shù):?內(nèi)存對(duì)齊? ? 循環(huán)展開 (局部性原理)? 批量copy

glibc庫(kù)函數(shù):

技術(shù):?內(nèi)存對(duì)齊? 批量copy ?

DPDK庫(kù)函數(shù):

技術(shù):?指令預(yù)取? 局部性原理? ?向量指令? cache對(duì)齊

注:?本文是我早期發(fā)表在CSDN上的文章,比較粗糙,現(xiàn)用公眾號(hào)記錄一下,希望和大家一起努力,朝頂級(jí)C程序員前進(jìn)

推薦閱讀

C++內(nèi)存管理全景指南

C++的最后一道坎|百萬(wàn)年薪的程序員

Linux調(diào)度系統(tǒng)全景指南(終結(jié)篇-調(diào)度優(yōu)化)

總結(jié)

以上是生活随笔為你收集整理的顶级C程序员之路的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 韩国三级hd中文字幕有哪些 | 日韩精品色 | 穿越异世荒淫h啪肉np文 | 青娱乐福利视频 | av导航网站 | 草逼网站| 在线视频一区二区 | 99在线精品免费视频 | 奇米在线视频 | 一级免费大片 | 精品97人妻无码中文永久在线 | 精品人妻一区二区三区日产乱码卜 | 国产欧美一区二区三区白浆喷水 | 国产精品第100页 | 丝袜视频一区 | 亚洲欧洲日本一区二区三区 | 极品蜜桃臀肥臀-x88av | 免费不卡视频 | 亚洲人一区二区三区 | 国产精品色 | 日韩三级在线免费观看 | 日韩怡春院 | 午夜激情福利视频 | 在线一区视频 | 久久久无码精品亚洲无少妇 | 欧美一区二区三区四区在线 | 先锋影音资源av | 久久久精品久久久久 | 天堂视频免费在线观看 | 日韩免费福利视频 | 相亲对象是问题学生在线观看 | 二级毛片 | 丰满人妻一区二区三区在线 | 久久久久亚洲日日精品 | 日日夜夜操操操 | 七七久久 | 潘金莲黄色一级片 | 国产夜夜夜 | 久久影院午夜 | 狠狠干美女 | 麻豆亚洲精品 | 久久综合影院 | 成年人理论片 | 成人动漫一区二区 | 浪浪视频污| 日日麻批免费视频播放 | 免费看女生裸体视频 | 精品一久久 | 狠狠操女人 | 青青青国产在线 | 免费成人av网址 | beeg日本高清xxxx18 | 亚洲视频免费在线 | 性欧美极品| 欧美一区二区黄片 | 青青草手机在线 | 久久香视频 | 国产无遮挡18禁无码网站不卡 | 午夜一区二区三区在线 | 91欧美国产| 偷拍夫妻性生活 | 三级免费网址 | 欧美视频二区 | 久久精品亚洲a | 欧美一级片在线观看 | 黄色裸体片 | 免费av免费看 | 天堂av资源在线观看 | 成人在线精品 | 麻豆人妻少妇精品无码专区 | 在线国产不卡 | 国产成人精品无码免费看在线 | 久久久久久一 | 打屁股视频网站 | 亚洲三级成人 | 久久有精品 | 91黑丝美女| 亚洲大胆视频 | 婷婷久久亚洲 | 在线色站 | xxx精品| 黄色成人在线免费观看 | 最新日韩三级 | 理论片久久 | 欧洲精品一区二区三区久久 | 荒野求生21天去码版网站 | 国产一区二区三区免费 | 伊人中文字幕在线观看 | 深夜福利免费在线观看 | 久久精品久久精品久久精品 | 国产美女永久无遮挡 | 午夜影院久久久 | 欧美性受xxxx黑人猛交88 | 欧美性爱精品一区 | 91视频福利 | 亚洲激情欧美 | 成人漫画网站 | 黄色片免费观看 | 亚洲四虎影院 |