顶级c程序员之路 选学篇-1 深入理解字节,字节序与字节对齐
?
?????????????????????????深入理解字節(jié),字節(jié)序與字節(jié)對(duì)齊
一?總述
???作為一個(gè)職業(yè)的coder玩家,首先應(yīng)該對(duì)計(jì)算機(jī)的字節(jié)有所了解。
???我們經(jīng)常談到的2進(jìn)制流,字節(jié)(字符)流,數(shù)據(jù)類(lèi)型流(針對(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次方(應(yīng)該和硬件有關(guān))。??這樣讀取字節(jié)的時(shí)候,開(kāi)銷(xiāo)不會(huì)太高,可以達(dá)到最大性能,因?yàn)閯傞_(kāi)始,計(jì)算機(jī)是美國(guó)發(fā)明的,西文字符(英文字母大小寫(xiě),數(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ù)類(lèi)型流,就是在c語(yǔ)言里面的數(shù)據(jù)類(lèi)型占多少個(gè)字節(jié)。然后直接操作數(shù)據(jù)類(lèi)型。在目前的32位系統(tǒng)中,c語(yǔ)言的基本數(shù)據(jù)類(lèi)型有以下幾種:
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)類(lèi)型?由于浮點(diǎn)類(lèi)型和整形的編碼不一樣,所以浮點(diǎn)型需要特殊分析。
Float?占4個(gè)字節(jié) ?
Double?占8個(gè)字節(jié)?
深入理解浮點(diǎn)類(lèi)型,請(qǐng)看這邊文章:
http://blog.csdn.net/caotiancool/archive/2005/04/29/368375.aspx?
主要是這不是這篇文章的重點(diǎn)。
進(jìn)入今天的主題
三?字節(jié)序
??為什么有字節(jié)序這個(gè)概念存在呢?
不同的CPU有不同的字節(jié)序類(lèi)型?這些字節(jié)序是指整數(shù)在內(nèi)存中保存的順序?這個(gè)叫做主機(jī)序?,就是多個(gè)字節(jié)在內(nèi)存中擺放位置順序和解釋順序。
最常見(jiàn)的有兩種?:
1.?Little?endian:將低序字節(jié)存儲(chǔ)在起始地址?4321
2.?Big?endian:將高序字節(jié)存儲(chǔ)在起始地址????1234
以前還有什么Middle?endian,就亂序,也被淘汰。
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ū)懗?
把值按照通常的高位到低位的順序?qū)懗?
兩者對(duì)照,一個(gè)字節(jié)一個(gè)字節(jié)的填充進(jìn)去?
例子:在內(nèi)存中雙字0x01020304(DWORD)的存儲(chǔ)方式?
內(nèi)存地址?
4000?4001?4002?4003?
LE?04?03?02?01?
BE?01?02?03?04?
例子:如果我們將0x1234abcd寫(xiě)入到以0x0000開(kāi)始的內(nèi)存中,則結(jié)果為
??????big-endian???little-endian
0x0000???0x12???????0xcd
0x0001???0x23???????0xab
0x0002???0xab???????0x34
0x0003???0xcd???????0x12
x86系列CPU都是little-endian的字節(jié)序.?
網(wǎng)絡(luò)字節(jié)順序是TCP/IP協(xié)議棧中規(guī)定好的一種數(shù)據(jù)表示格式,它與具體的CPU類(lèi)型、操作系統(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類(lèi)型從主機(jī)序轉(zhuǎn)換到網(wǎng)絡(luò)序
htonl?把unsigned?long類(lèi)型從主機(jī)序轉(zhuǎn)換到網(wǎng)絡(luò)序
ntohs?把unsigned?short類(lèi)型從網(wǎng)絡(luò)序轉(zhuǎn)換到主機(jī)序
ntohl?把unsigned?long類(lèi)型從網(wǎng)絡(luò)序轉(zhuǎn)換到主機(jī)序
在使用little?endian的系統(tǒng)中?這些函數(shù)會(huì)把字節(jié)序進(jìn)行轉(zhuǎn)換?
在使用big?endian類(lèi)型的系統(tǒng)中?這些函數(shù)會(huì)定義成空宏
?都是4個(gè)宏函數(shù):
?分析其中1個(gè),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)\
))
這樣寫(xiě)是方便好看一點(diǎn),宏的最后最好是用一個(gè)括號(hào)括起來(lái),或者用do{}while(0)包起來(lái)。
這樣可以防止宏嵌套產(chǎn)生意想不到問(wèn)題等,如果自己熟悉了就可以簡(jiǎn)潔一點(diǎn)。上面那個(gè)宏的作用是把4321變成1234(字節(jié)擺放順序)。
一般c語(yǔ)言編寫(xiě)程序的字節(jié)序都是系統(tǒng)相關(guān)的(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)換,跨平臺(tái)開(kāi)發(fā)時(shí)也應(yīng)該注意保證只用一種字節(jié)序?不然兩方的解釋不一樣就會(huì)產(chǎn)生bug。
網(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;
?? ? ?}?
}?
注:
1、網(wǎng)絡(luò)與主機(jī)字節(jié)轉(zhuǎn)換函數(shù):htons?ntohs?htonl?ntohl?(s?就是short?l是long?h是host?n是network)
2、不同的CPU上運(yùn)行不同的操作系統(tǒng),字節(jié)序也是不同的,參見(jiàn)下表。
處理器?????????操作系統(tǒng)?????字節(jié)排序
Alpha????????????全部?????Little?endian
HP-PA?????????????NT??????Little?endian
HP-PA????????????UNIX?????Big?endian
Intelx86?????????全部?????Little?endian?<-----x86系統(tǒng)是小端字節(jié)序系統(tǒng)
Motorola680x()???全部?????Big?endian
MIPS??????????????NT??????Little?endian
MIPS?????????????UNIX?????Big?endian
PowerPC???????????NT??????Little?endian
PowerPC??????????非NT?????Big?endian???<-----PPC系統(tǒng)是大端字節(jié)序系統(tǒng)
RS/6000??????????UNIX?????Big?endian
SPARC????????????UNIX?????Big?endian
IXP1200?ARM核心??全部?????Little?endian?
四?字節(jié)對(duì)齊
首先我看哈程序的優(yōu)化種類(lèi):
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ì)任何類(lèi)型的變量的訪問(wèn)可以從任何地址開(kāi)始,但實(shí)際情況是在訪問(wèn)特定類(lèi)型變量的時(shí)候經(jīng)常在特定的內(nèi)存地址訪問(wèn),這就需要各種類(lèi)型數(shù)據(jù)按照一定的規(guī)則在空間上排列,而不是順序的一個(gè)接一個(gè)的排放,這就是對(duì)齊。?
????對(duì)齊的作用和原因:各個(gè)硬件平臺(tái)對(duì)存儲(chǔ)空間的處理上有很大的不同。一些平臺(tái)對(duì)某些特定類(lèi)型的數(shù)據(jù)只能從某些特定地址開(kāi)始存取。比如有些架構(gòu)的CPU在訪問(wèn)一個(gè)沒(méi)有進(jìn)行對(duì)齊的變量的時(shí)候會(huì)發(fā)生錯(cuò)誤(比如高通平臺(tái),一般的手機(jī)平臺(tái)都采用美國(guó)高通公司開(kāi)發(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)每次讀都是從偶地址開(kāi)始,如果一個(gè)int型(假設(shè)為32位系統(tǒng))如果存放在偶地址開(kāi)始的地方,那?么一個(gè)讀周期就可以讀出這32bit,而如果存放在奇地址開(kāi)始的地方,就需要2個(gè)讀周期,并對(duì)兩次讀出的結(jié)果的高低字節(jié)進(jìn)行拼湊才能得到該32bit數(shù)據(jù)。顯然在讀取效率上下降很多。?
一般的規(guī)則是,
1?對(duì)于基本數(shù)據(jù)類(lèi)型對(duì)齊要求:
Char?類(lèi)型一個(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整除。
在c語(yǔ)言中存在struct和union結(jié)構(gòu)體類(lèi)型,屬于復(fù)雜類(lèi)型:
2??對(duì)于struct和union對(duì)齊要求是:
其成員中自身對(duì)齊值最大的那個(gè)值?。
注:結(jié)構(gòu)的總大小為結(jié)構(gòu)的字節(jié)邊界數(shù)(即該結(jié)構(gòu)中占用最大空間的變量的類(lèi)型所占用的字節(jié)數(shù))的倍數(shù),對(duì)于結(jié)構(gòu)體最終大小,還要參考,指定對(duì)齊值n。
1)對(duì)于struct我們有:
s表示這個(gè)結(jié)構(gòu)體,X(i)表示其第i個(gè)成員(按順序從上往下)所占的大小;假使結(jié)構(gòu)體有m個(gè)成員;
結(jié)構(gòu)體的最終對(duì)齊值??
??其中基本類(lèi)型對(duì)齊值:
??A(char)?=?1;
??A(short)?=?2;
??A(int)?=?4;
??A(long)?=?4;
??A(float)?=?4;
??A(double)?=?8;
?
????基本類(lèi)型成員對(duì)齊值?A(x)?=?min(A(type),n?);????公式1
A(type)?為基本類(lèi)型成員x?對(duì)應(yīng)的基本類(lèi)型。
?????A(s)?=?min(max(A(1),A(2),...,A(m)),n)???????公式2
(這個(gè)一個(gè)遞歸函數(shù),主要原因是成員Xi有可能也是一個(gè)結(jié)構(gòu)體,嵌套類(lèi)型)
?其中:
?由規(guī)則1可以得到公式?2的初始值
??struct結(jié)構(gòu)體最終占內(nèi)存大小Xs:
??定義H(x)表示前面x個(gè)成員最終占內(nèi)存大小;A(x)表示第x個(gè)成員的對(duì)齊值。可以有公式1給出,則:
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)?=?X1,A(1)=?X1;??
????????????????????????????????????公式3
?
則:
If(H(m)%A(s)?==?0)
???Xs?=?H(m);
Else
???Xs?=?H(m)+A(s)-H(m)%A(s);?
?
????????????????????????????????????公式4?
2)對(duì)于union我們有:
?????U表示這個(gè)結(jié)構(gòu)體,Xi表示其第i個(gè)成員(按順序從上往下)所占的大小;假使結(jié)構(gòu)體有m個(gè)成員;
??????結(jié)構(gòu)體的最終對(duì)齊值??A(u)?=?min(max(A(1),A(2),...,A(m)),n)?公式5
Union結(jié)構(gòu)體最終占內(nèi)存大小Xu:
???定義H(x)表示前面x個(gè)成員最終占內(nèi)存大小;A(x)表示第x個(gè)成員的對(duì)齊值。可以有公式1給出,則:
??H(x+1)=?max(X(x+1),?H(x));
其中?H(1)?=?X1;
?
????????????????????????????????????公式6
???則:
If(H(m)%A(u)?==?0)
???Xu?=?H(m);
Else
???Xu?=?H(m)+A(u)-H(m)%A(u);?
?
????????????????????????????????????公式7?
?
3??指定對(duì)齊值:
?????如果我們想指定對(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è)值?。(這個(gè)很重要,請(qǐng)好好理解)。
?
4??結(jié)構(gòu)中帶有結(jié)構(gòu)
????不必考慮整個(gè)子結(jié)構(gòu),只考慮子結(jié)構(gòu)的基本類(lèi)型并參照前面的規(guī)則來(lái)分配空間。
?空結(jié)構(gòu)(即不帶任何的方法和數(shù)據(jù))占用的1字節(jié)的空間。
5??枚舉中(enum)?
???枚舉始終占用4字節(jié)的空間。
?
6??結(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)?span style="font-family:'Times New Roman'">H(2)%A(3)==0;
所以?H(3)?=(H(2))?10+4?=?14;
因?yàn)?span style="font-family:'Times New Roman'">H(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(s3)?=?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;
具體過(guò)程自己可以分析一下;
?例子?4:
#pragma?pack(4)
union?u1
{
double?b;?A(1)??=?4
int?a;????A(2)??=?4
}x1;
#pragma?pack()
#pragma?pack(8)
union?u2
{
char?a[13];?A(1)?=?1
double?b;??A(2)?=?8
}x2;
#pragma?pack()
A(u1)??=?min(max(A(1),A(2))=4,n=4)?=?4;
A(u2)??=min(max(A(1),A(2))=8,n=8)?=?8;
對(duì)于u1,H(1)?=?8;?H(2)?=?max(H(1)8,X(2)4)?=?8;
因?yàn)?span style="font-family:'Times New Roman'">H(2)%A(u1)?==?0;
所以?X(u1)?=?H(2)?=?8;
對(duì)于u2,H(1)?=?13,?H(2)=max(H(1),X(2)8)?=?13;
因?yàn)?H(2)%A(u2)?!=0;
所以?X(u2)?=?H(2)?+?A(u2)-H(2)%A(u2)=?13+3=16;
也上只是一些測(cè)試?yán)?#xff0c;真實(shí)的結(jié)構(gòu)體都比較龐大,一般用sizeof就可以了,但心里要清楚,每個(gè)成員的偏移量和填充的字節(jié),這些都可以由上面的公式推出來(lái),我這里就暫時(shí)不推導(dǎo)了(但這個(gè)才是我們平時(shí)最應(yīng)該注意的)。
五?總結(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)制類(lèi)型轉(zhuǎn)換或者按偏移量訪問(wèn)變量,就有可能出現(xiàn)錯(cuò)誤(某些嵌入式cpu)或者意想不到問(wèn)題,所以對(duì)于嵌入式開(kāi)發(fā)的程序員最好是心里有數(shù)。
????最后請(qǐng)希望自己成為頂級(jí)c程序員的coders,來(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ù),而且里面充滿奇淫巧計(jì),呵呵,看看自己會(huì)長(zhǎng)見(jiàn)識(shí)。
以下是高通平臺(tái)的memcpy函數(shù):
typedef??unsigned?int?uint_t;
typedef??unsigned?char?uchar_t;
void?*
memcpy(void?*?d,?const?void?*s,size_t?n)
{
???size_t?i;
???uint_t?align?=?sizeof(uint_t?)?-1;
???if(?((uint_t)d&align)|?((uint_t)s&align)|?(n&align))
??{
?????uchar_t??*dest?=?(uchar_t??*)d;
?????uchar_t??*src?=?(uchar_t??*)s;
?????for(i?=?0;?i?<?n;?++i)
?????{
????????*dest?++?=?*src++;
?????}
?}
?else
?{
?????uint_t??*dest?=?(uint_t?*)d;
?????uint_t??*src?=?(uint_t?*)d;
?????n?/=sizeof(uint_t?);
?????for(i?=?1;?i?<?n;?++i)
??????{
????????*dest?++?=?*src++;
??????}
?}
?return?d;
}
?
注:?以上只是我學(xué)習(xí)中文檔輸出,可能會(huì)有錯(cuò)誤(什么類(lèi)型的錯(cuò)誤都可能發(fā)生),我希望讀者能幫我一起改正,希望大家一起努力,朝頂級(jí)c程序員前進(jìn),讀者有什么意見(jiàn)都可以在回復(fù)中提出,我會(huì)繼續(xù)的,就像我前一篇文章所說(shuō)一樣,目的把我學(xué)到的東西分享給大家,希望大家好好學(xué)
?
總結(jié)
以上是生活随笔為你收集整理的顶级c程序员之路 选学篇-1 深入理解字节,字节序与字节对齐的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 《深入理解Kafka:核心设计与实践原理
- 下一篇: 顶级c程序员之路 基础篇 - 第一章 关