C進(jìn)階:拿著"sizeof這些用法和坑"去吹牛吧!
1、聊一聊
? ??本文跟大家分享的是C語(yǔ)言中sizeof一些需要注意的知識(shí)點(diǎn),一方面可以避免大家再次掉坑,另一方面可以拿去吹吹牛!
2、正確認(rèn)識(shí)sizeof
? ??
? ? 首先大家需要明確,sizeof不是一個(gè)函數(shù)而是一個(gè)操作符,一些小伙伴經(jīng)??陬^上掛著"sizeof函數(shù)",這種說(shuō)法是不正確的。
? ? 應(yīng)該也好理解,比如sizeof(int),里面并沒有傳遞實(shí)參,如果其為函數(shù)便不成立,所以sizeof僅僅只是一個(gè)操作符,繼續(xù)實(shí)驗(yàn)一下:
參考demo:
1#include?
2#include?
3
4/***************************************
5?*?Fuction:?sizeof簡(jiǎn)單測(cè)試?
6?*?Author:???(公眾號(hào):最后一個(gè)bug)?
7?**************************************/
8int?main(int?argc,?char?*argv[])?{
9????int?a?=?5;?
10????printf("sizeof(char)=?%d\n",sizeof(char));
11????printf("sizeof(int)=?%d\n",sizeof(int));
12????printf("sizeof(float)=?%d\n",sizeof(float));
13????printf("sizeof(double)=?%d\n",sizeof(double));
14????printf("sizeof(a)=?%d\n",sizeof(a));
15????return?0;
16}
匯編與結(jié)果:
分析一下:
匯編中5個(gè)紅線標(biāo)記處對(duì)應(yīng)著C語(yǔ)言中5個(gè)sizeof使用點(diǎn),在最終的匯編代碼中并沒有看到sizeof的痕跡。
同時(shí)還可以確認(rèn)一點(diǎn)的是sizeof在編譯階段就完成了轉(zhuǎn)化,所以經(jīng)常有小伙伴考慮到sizeof會(huì)不會(huì)很耗時(shí)間等等,從這里看它僅僅只是一個(gè)常量,對(duì)程序的運(yùn)行影響與常量是一致的。
?
? ? 因?yàn)樵诓煌钠脚_(tái)或者是編譯器,這些基礎(chǔ)的數(shù)據(jù)類型所占用的內(nèi)存字節(jié)空間不一定是相同的。
? ? sizeof功能就是計(jì)算出數(shù)據(jù)類型在內(nèi)存空間所占的字節(jié)數(shù),這樣就增強(qiáng)了程序的可移植性,特別是當(dāng)我們進(jìn)行內(nèi)存拷貝的時(shí)候顯得尤為有用。
? ? 比如一個(gè)大型結(jié)構(gòu)體數(shù)據(jù)的內(nèi)存拷貝,當(dāng)由于內(nèi)存數(shù)據(jù)類型發(fā)生變化,或者是數(shù)據(jù)對(duì)齊等等原因?qū)е略摻Y(jié)構(gòu)體所占內(nèi)存發(fā)生變化,如果你采用的memcpy函數(shù)指定的大小沒有跟隨發(fā)生改變,則會(huì)出現(xiàn)問(wèn)題,如下面示例:
參考demo:
1#include?
2#include?
3#include?
4
5//采用默認(rèn)對(duì)齊?
6typedef?struct?_tag_Test1
7{
8????char?Val1;
9????int??Val2;
10????char?Val3;??
11}sTest1;
12
13sTest1?stTest1={1,2,3};
14
15//采用一個(gè)字節(jié)對(duì)齊?
16#pragma?pack(1)
17typedef?struct?_tag_Test2
18{
19????char?Val1;
20????int??Val2;
21????char?Val3;??
22}sTest2;
23
24#pragma?pack(0)
25sTest2?stTest2={4,5,6};
26/***************************************
27?*?Fuction:?sizeof可移植性?
28?*?Author:???(公眾號(hào):最后一個(gè)bug)?
29?**************************************/
30int?main(int?argc,?char?*argv[])?{
31
32????sTest1?stTest1_ds;
33????sTest2?stTest2_ds;?
34
35????printf("sizeof(sTest1)?=?%d\n",sizeof(sTest1));
36????printf("sizeof(sTest2)?=?%d\n",sizeof(sTest2));
37
38??//?memcpy(&stTest1_ds,&stTest1,12);??//12和6硬編程,可移植性不好?
39??//?memcpy(&stTest2_ds,&stTest2,6);
40
41????memcpy(&stTest1_ds,&stTest1,sizeof(sTest1));
42????memcpy(&stTest2_ds,&stTest2,sizeof(sTest2));
43
44????printf("%d??%d??%d\n",stTest1_ds.Val1,stTest1_ds.Val2,stTest1_ds.Val3);
45????printf("%d??%d??%d\n",stTest2_ds.Val1,stTest2_ds.Val2,stTest2_ds.Val3);
46
47????return?0;
48}
輸出結(jié)果:
分析一下:
上面bug菌為了解釋結(jié)構(gòu)體在不同平臺(tái)占用空間有所不同,通過(guò)設(shè)置結(jié)構(gòu)體對(duì)齊來(lái)進(jìn)行了模擬(如何設(shè)置結(jié)構(gòu)體對(duì)其字節(jié)個(gè)數(shù)可要學(xué)會(huì)!),使用sizeof明顯要比硬編程的移植性更好。
結(jié)構(gòu)體對(duì)齊不太不理解的可以參考<聽說(shuō)因?yàn)榇a沒"對(duì)齊"程序就奔了?(深度剖析)>。
? ? 在之前的文中bug菌講到了strlen返回的是size_t類型,其為無(wú)符號(hào)類型,參考<【C進(jìn)階】一不小心就被"strlen"給坑了!>,那么sizeof編譯器會(huì)處理成什么類型呢? 不防做個(gè)實(shí)驗(yàn):
參考demo:
1#include?
2#include?
3
4/***************************************
5?*?Fuction:?sizeof類型測(cè)試?
6?*?Author:???(公眾號(hào):最后一個(gè)bug)?
7?**************************************/
8int?main(int?argc,?char?*argv[])?{
9
10????int?i=?-1;
11
12????if(i?>?sizeof(int))
13????{
14????????printf("sizeof?采用無(wú)符號(hào)類型\n");???
15????}
16????else
17????{
18????????printf("sizeof?采用有符號(hào)類型\n");???
19????}?
20
21????return?0;
22}
輸出結(jié)果:
分析一下:
-1 > 4的結(jié)果是C語(yǔ)言進(jìn)行了自動(dòng)類型轉(zhuǎn)化,不理解的可參考<【重磅】“整形數(shù)”還真沒那么簡(jiǎn)單(C語(yǔ)言版)>;
sizeof和strlen函數(shù)的返回類型一樣,都是size_t類型(可能有些平臺(tái)指定為unsigned int),而該類型一般定義無(wú)符號(hào)整形,這樣也就會(huì)出現(xiàn)如上的實(shí)驗(yàn)現(xiàn)象,以后多加小心。其實(shí)也很好理解,它們都是計(jì)算數(shù)據(jù)長(zhǎng)度的方法也就沒有必要使用有符號(hào)類型。
這里提到strlen與sizeof,也是經(jīng)常使用過(guò)程中容易混淆的,這兩者有些相似也有不同,不過(guò)大家只要從定義出發(fā)就沒有問(wèn)題了,如下Demo:
1#include?
2#include?
3
4/***************************************
5?*?Fuction:?sizeof與strlen?
6?*?Author:???(公眾號(hào):最后一個(gè)bug)?
7?**************************************/
8int?main(int?argc,?char?*argv[])?{
9
10????char?*?cbug?=?"bug";?
11
12????printf("sizeof(cbug)?=?%d\n",sizeof(cbug));?//?b?u?g?\n?
13
14????printf("strlen(cbug)?=?%d\n",strlen(cbug));?//?b?u?g?
15
16????return?0;
17}
? ? 這一點(diǎn)大家可能會(huì)疑惑,這里所說(shuō)的單一不是說(shuō)功能單一,而是sizeof只在編譯階段檢測(cè)并計(jì)算其后的類型,其他表達(dá)式均不處理,見代碼見真相 :
參考demo:
1#include?
2#include?
3
4/***************************************
5?*?Fuction:??Cal?
6?*?Author:???(公眾號(hào):最后一個(gè)bug)?
7?**************************************/
8int?Cal(int?*param1,int?*param2,int?*result)
9{
10????*result?=?*param1?+?*param2;
11?????return?1;
12}?
13
14/***************************************
15?*?Fuction:?sizeof重點(diǎn)實(shí)例?
16?*?Author:???(公眾號(hào):最后一個(gè)bug)?
17?**************************************/
18int?main(int?argc,?char?*argv[])?{
19
20????int?i?=?1;?
21????char?j?=?1;?
22????int?a?=?2;
23????int?b?=?2;
24????int?ret?=?0;
25
26????printf("sizeof(i++)??=?%d\n",sizeof(i++));??
27????printf("sizeof(++i)??=?%d\n",sizeof(++i));??
28????printf("sizeof?++i???=?%d\n",sizeof?++j);???
29
30????printf("sizeof(Cal)??=?%d\n",sizeof(Cal(&a,&b,&ret)));
31????printf("sizeof?Cal???=?%d\n",sizeof?Cal(&a,&b,&ret));?
32
33????printf("i????????????=?%d\n",i);
34????printf("j????????????=?%d\n",j);????
35????printf("ret??????????=?%d\n",ret);??
36????return?0;
37}
輸出結(jié)果:
分析一下:
通過(guò)上面的實(shí)驗(yàn)大家可以發(fā)現(xiàn)sizeof后的表達(dá)式均沒有執(zhí)行,編譯器把sizeof修飾部分通過(guò)計(jì)算其類型占用空間大小直接替換。
所以很多小伙伴編碼比較隨意容易出現(xiàn)這種類型的bug,當(dāng)然sizeof后面接具體的數(shù)據(jù)類型一定需要小括號(hào),而是其他非void表達(dá)式均可以省略該小括號(hào),上面的實(shí)例中為大家展示了。
? ? 最后兩個(gè)小細(xì)節(jié):
1 )?sizeof(數(shù)組名)和sizeof(指針)的差別。前者為總的數(shù)組字節(jié)個(gè)數(shù),而后者僅為平臺(tái)指針?biāo)甲止?jié)個(gè)數(shù)。
2 )?sizeof不能用來(lái)計(jì)算位域大小。其實(shí)也很好理解,sizeof僅僅只計(jì)算字節(jié)個(gè)數(shù),位域bit個(gè)數(shù)編譯器不識(shí)別。
前提條件
現(xiàn)以上內(nèi)容暫不考慮C99標(biāo)準(zhǔn)下的sizeof的使用情況。
由于在C99標(biāo)準(zhǔn)下存在不定長(zhǎng)數(shù)組的使用,從而使得sizeof會(huì)在程序運(yùn)行階段確定對(duì)應(yīng)的類型字節(jié)個(gè)數(shù)
5、結(jié)束語(yǔ)
? ? 本文到這里就結(jié)束了,sizeof理解好了其實(shí)并不難,就怕你閱讀一些反人類的代碼,從而造成理解上的困難!當(dāng)然面試官也可能考你一波!
????好了,這里是公眾號(hào):“最后一個(gè)bug”,一個(gè)為大家打造的技術(shù)知識(shí)提升基地。
推薦好文??點(diǎn)擊藍(lán)色字體即可跳轉(zhuǎn)
【開源】bug菌把"動(dòng)態(tài)數(shù)字顯示"開源了!
【嵌入式】bug粉碎機(jī)之volatile的那些坑
【MCU】用stm32的UID給固件加密(重點(diǎn)在加密)
【硬核C進(jìn)階】如何實(shí)現(xiàn) 萬(wàn)能 "兩數(shù)交換" 宏 ?
?【進(jìn)階】同事用#include"xxx.c"把我給驚呆了??!
免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。文章僅代表作者個(gè)人觀點(diǎn),不代表本平臺(tái)立場(chǎng),如有問(wèn)題,請(qǐng)聯(lián)系我們,謝謝!