在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

關(guān)于你可能不知道的printf

黃工的嵌入式技術(shù)圈 ? 來(lái)源:黃工的嵌入式技術(shù)圈 ? 作者:黃工的嵌入式技術(shù) ? 2020-02-05 12:28 ? 次閱讀

前言

printf可能是我們?cè)趯W(xué)習(xí)C語(yǔ)言的過(guò)程中最早接觸的庫(kù)函數(shù)了。其基本使用想必我們都已經(jīng)非常清楚了。但是下面的這些情況你是否已經(jīng)清楚地知道了呢?

示例程序

我們來(lái)看一個(gè)示例程序,看看你能否對(duì)下面的結(jié)果輸出有非常清晰的認(rèn)識(shí)。

#include intmain(void) { inta=4; intb=3; intc=a/b; floatd=*(float*)(&c); longlonge=0xffffffffffffffff; printf("a/b:%f,a:%d\n",a/b,a,b);//打印0 printf("(float)a/b:%f\n",((float)a)/b);//打印1 printf("(double)a/b:%lf\n",((double)a)/b);//打印2 printf("d:%f\n",d);//打印3 printf("%.*f\n",20,(double)a/b);//打印4 printf("e:%d,a:%d\n",e,a);//打印5 printf("a:%d,++a:%d,a++:%d\n",a,++a,a++);//打印6 return0; }

編譯為32位程序:

gcc-m32-otesttest.c

在運(yùn)行之前,你可以自己先猜想一下打印結(jié)果會(huì)是什么。實(shí)際運(yùn)行結(jié)果:

a/b:0.000000,a:3//打印0的結(jié)果 (float)a/b:1.333333//打印1的結(jié)果 (double)a/b:1.333333//打印2的結(jié)果 d:0.000000//打印3的結(jié)果 1.33333333333333325932//打印4的結(jié)果 e:-1,a:-1//打印5的結(jié)果 a:6,++a:6,a++:4//打印6的結(jié)果

你的猜想是否都正確呢?如果猜想錯(cuò)誤,那么接下來(lái)的內(nèi)容你就不應(yīng)該錯(cuò)過(guò)了。

你是否會(huì)有以下疑問(wèn):

0.打印0的a/b為什么不是1,a為什么不是4?

1.打印1和打印2有什么區(qū)別呢?

2.打印3為什么結(jié)果會(huì)是0.000000?

3.打印4的結(jié)果為什么最后的小數(shù)位不對(duì)?其中的*是什么意思?

4.打印5中,為什么a的值是-1而不是4?

5.打印6中,結(jié)果為什么分別是6,6,4?

在解答這些問(wèn)題之前,我們需要先了解一些基本內(nèi)容。

可變參數(shù)中的類型提升

printf是接受變長(zhǎng)參數(shù)的函數(shù),傳入printf中的參數(shù)個(gè)數(shù)可以不定。而我們?cè)谧冮L(zhǎng)參數(shù)探究中說(shuō)到:
調(diào)用者會(huì)對(duì)每個(gè)參數(shù)執(zhí)行“默認(rèn)實(shí)際參數(shù)提升",提升規(guī)則如下:
——float將提升到double
——char、short和相應(yīng)的signed、unsigned類型將提升到int

也就是說(shuō)printf實(shí)際上只會(huì)接受到double,int,long int等類型的參數(shù)。而從來(lái)不會(huì)實(shí)際接受到float,char,short等類型參數(shù)。
我們可以通過(guò)一個(gè)示例程序來(lái)檢驗(yàn):

//badcode #include intmain(void) { char*p=NULL; printf("%d,%f,%c\n",p,p,p); return0; }

編譯報(bào)錯(cuò)如下:

printf.c:Infunction‘main’: printf.c:5:12:warning:format‘%d’expectsargumentoftype‘int’,butargument2hastype‘char*’[-Wformat=] printf("%d,%f,%c\n",p,p,p); ^ printf.c:5:12:warning:format‘%f’expectsargumentoftype‘double’,butargument3hastype‘char*’[-Wformat=] printf.c:5:12:warning:format‘%c’expectsargumentoftype‘int’,butargument4hastype‘char*’[-Wformat=]

我們可以從報(bào)錯(cuò)信息中看到:

%d 期望的是 int 類型參數(shù)

%f 期望的是 double 類型參數(shù)

%c 期望的也是 int 類型參數(shù)

而編譯之所以有警告是因?yàn)椋琧har *類型無(wú)法通過(guò)默認(rèn)實(shí)際參數(shù)提升,將其提升為int或double。

參數(shù)入棧順序以及計(jì)算順序

在C語(yǔ)言中,參數(shù)入棧順序是確定的,從右往左。而參數(shù)的計(jì)算順序卻是沒(méi)有規(guī)定的。也就是說(shuō),編譯器可以實(shí)現(xiàn)從右往左計(jì)算,也可以實(shí)現(xiàn)從左往右計(jì)算。

浮點(diǎn)數(shù)的有效位

對(duì)于double類型,其有效位為15~~16位(參考:對(duì)浮點(diǎn)數(shù)的一些理解)。

可變域?qū)捄途?/p>

printf中,*的使用可實(shí)現(xiàn)可變域?qū)捄途龋褂脮r(shí)只需要用*替換域?qū)捫揎椃途刃揎椃纯伞T谶@樣的情況下,printf會(huì)從參數(shù)列表中取用實(shí)際值作為域?qū)捇蛘呔取J纠绦蛉缦拢?/p>

#include intmain(void) { floata=1.33333333; char*p="hello"; printf("%.*f\n",6,a); printf("%*s\n",8,p); return0; }

運(yùn)行結(jié)果:

1.333333 hello

而這里的6或者8完全可以是一個(gè)宏定義或者變量,從而做到了動(dòng)態(tài)地格式控制。

格式控制符是如何處理參數(shù)的

printf有很多格式控制符,例如%d,它在處理輸入時(shí),會(huì)從堆棧中取其對(duì)應(yīng)大小,即4個(gè)字節(jié)作為對(duì)應(yīng)的參數(shù)值。也就是說(shuō),當(dāng)你傳入?yún)?shù)和格式控制符匹配或者在經(jīng)過(guò)類型提升后和格式控制符匹配的時(shí)候,參數(shù)處理是沒(méi)有任何問(wèn)題的。但是不匹配時(shí),可能會(huì)出現(xiàn)未定義行為(有兩種情況例外,我們后面再說(shuō))。例如,%f期望一個(gè)double(8字節(jié))類型,但是傳入的參數(shù)是int(4字節(jié)),那么在處理這個(gè)int參數(shù)值,可能會(huì)多處理4個(gè)字節(jié),并且也會(huì)造成處理數(shù)據(jù)錯(cuò)誤。

真相大白

有了前面這些內(nèi)容的鋪墊,我們?cè)賮?lái)解答開(kāi)始的疑問(wèn):

對(duì)于問(wèn)題0,a/b的結(jié)果顯然為4字節(jié)的int類型1,而%f期望的是8字節(jié)的double,而計(jì)算結(jié)果只有4個(gè)字節(jié),因此會(huì)繼續(xù)格式化后面4個(gè)字節(jié)的a,而整型1和后面a組合成的8字節(jié)數(shù)據(jù),按照浮點(diǎn)數(shù)的方式解釋時(shí),它的值就是0.000000了。由于前面已經(jīng)讀取解釋了a的內(nèi)容,因此第二個(gè)%d只能繼續(xù)讀取4個(gè)字節(jié),也就是b的值3,最終就會(huì)出現(xiàn)打印a的值是3,而不是4。

對(duì)于問(wèn)題1,實(shí)際上在printf中,是不需要%lf的,%f期望的就是double類型,在編譯最開(kāi)始的示例程序其實(shí)就可以發(fā)現(xiàn)這個(gè)事實(shí)。當(dāng)然了在scanf函數(shù)中,這兩者是有區(qū)別的。

對(duì)于問(wèn)題2,也很簡(jiǎn)單,2的二進(jìn)制存儲(chǔ)形式按照浮點(diǎn)數(shù)方式解釋讀取時(shí),就是該值。

對(duì)于問(wèn)題3,double的有效位為15~16位,也就是之外的位數(shù)都是不可靠的。printf中的*可用于實(shí)現(xiàn)可變域?qū)捄途龋懊嬉呀?jīng)解釋過(guò)了。

對(duì)于問(wèn)題4,這里不給出,留給讀者思考,歡迎大家可留言區(qū)給出原因。

對(duì)于問(wèn)題5,雖然參數(shù)計(jì)算順序沒(méi)有規(guī)定,但是實(shí)際上至少對(duì)于gcc來(lái)說(shuō),它是從右往左計(jì)算的。也就是說(shuō),先計(jì)算a++,而a++是先用在加,即壓入a=4,其后,a的值變?yōu)?;再計(jì)算++a,先加再用,即壓入a=5+1=6;最后a=6,壓入棧。最終從左往右壓入棧的值就分別為6,6,4。也就是最終的打印結(jié)果。但是實(shí)際情況中,這樣的代碼絕對(duì)不該出現(xiàn)!

至此,真相大白。

總結(jié)

雖然我們前面解釋了那些難以理解的現(xiàn)象,同時(shí)讀者可以參考變長(zhǎng)參數(shù)探究和對(duì)浮點(diǎn)數(shù)的一些理解找到更多的信息。但是我們?cè)趯?shí)際編程中應(yīng)該注意以下幾點(diǎn):

格式控制符應(yīng)該與對(duì)應(yīng)參數(shù)類型匹配或者與類型提升后的參數(shù)類型匹配。

絕對(duì)避免出現(xiàn)計(jì)算結(jié)果與參數(shù)計(jì)算順序有關(guān)的代碼。

*在printf中實(shí)現(xiàn)可變域?qū)捄途取?/p>

printf不會(huì)實(shí)際接受到char,short和float類型參數(shù)。

如果%s對(duì)應(yīng)的參數(shù)可能為NULL或者對(duì)應(yīng)整型,那將是一場(chǎng)災(zāi)難。

不要忽略編譯器的任何警告,除非你很清楚你在做什么。

例外情況指的是有符號(hào)整型和無(wú)符號(hào)整型之間,以及void*和char*之間。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 打印
    +關(guān)注

    關(guān)注

    1

    文章

    66

    瀏覽量

    18965
  • 程序
    +關(guān)注

    關(guān)注

    117

    文章

    3824

    瀏覽量

    82504
  • Printf
    +關(guān)注

    關(guān)注

    0

    文章

    84

    瀏覽量

    14131
收藏 人收藏

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    不知道怎么畫原理圖了

    時(shí),這樣的問(wèn)題,也有這么多?!1、電阻的表示方法是第一種,還是第二種?中間是方框還是折線?方框做多大?現(xiàn)場(chǎng)一片混亂立馬分成N派。普通的電阻都這樣,這么多種電阻現(xiàn)
    的頭像 發(fā)表于 04-30 18:40 ?276次閱讀
    <b class='flag-5'>不知道</b>怎么畫原理圖了

    PCB設(shè)計(jì)仿真,“縫合電容”我怎么可能不知道

    。 案例1: 相信很多人都遇到走線跨分割地平面的情況,例如下面的模型所展示的: 大家都知道跨分割肯定對(duì)信號(hào)有影響了,那你們能想到的優(yōu)化方案是什么呢!什么,告訴我不跨分割平面不就解決了嗎!要是能不
    發(fā)表于 04-28 15:44

    PCB設(shè)計(jì)仿真,“縫合電容”我怎么可能不知道

    說(shuō)到“縫合電容”,雖然我已經(jīng)聽(tīng)你們說(shuō)過(guò)800多遍了,但是還是忍不住問(wèn)一個(gè)很簡(jiǎn)單的問(wèn)題:額,它到底是啥。。。
    的頭像 發(fā)表于 04-28 15:43 ?146次閱讀
    PCB設(shè)計(jì)仿真,“縫合電容”我怎么<b class='flag-5'>可能不知道</b>

    球壓試驗(yàn)裝置:可能不知道的電氣安全衛(wèi)士

    球壓試驗(yàn)裝置,簡(jiǎn)單來(lái)說(shuō),是一種用于評(píng)估材料在高溫和壓力共同作用下抗形變能力的專業(yè)設(shè)備 。其核心測(cè)試原理基于一個(gè)看似簡(jiǎn)單卻極為精妙的設(shè)計(jì):將一個(gè)規(guī)定直徑(通常為 5mm)的鋼球,在特定壓力(一般為 20N±0.2N )下,壓在被測(cè)試材料表面,并將整個(gè)裝置置于設(shè)定高溫的烘箱中保持一段時(shí)間(常見(jiàn)為 60 分鐘) 。測(cè)試結(jié)束后,通過(guò)測(cè)量材料表面留下的壓痕直徑,來(lái)判斷
    的頭像 發(fā)表于 04-24 13:33 ?247次閱讀
    球壓試驗(yàn)裝置:<b class='flag-5'>你</b><b class='flag-5'>可能不知道</b>的電氣安全衛(wèi)士

    ADS805E測(cè)量跳躍幅度很大,不知道是為什么?

    我按照手冊(cè)上直流耦合連接電路,輸入是1.5V~3.5V范圍,SEL與VREF相連,用430定時(shí)器輸出轉(zhuǎn)換時(shí)鐘,結(jié)果測(cè)量直流時(shí),AD測(cè)量結(jié)果在幾個(gè)值之間跳躍,跳躍幅度很大,不知道是為什么,引腳電壓控制用3.3V。
    發(fā)表于 01-21 07:46

    測(cè)的值不定然后開(kāi)始減小直到為0,不知道怎么回事?

    ADS1247對(duì)寄存器可讀可寫 可是配置完02這個(gè)地址的時(shí)(寫0x30)在vrefout測(cè)不到2.048v,測(cè)的值不定然后開(kāi)始減小直到為0,不知道怎么回事?
    發(fā)表于 01-21 06:27

    有關(guān)UV固化不知道的技術(shù)細(xì)節(jié)

    UV固化技術(shù)中,光引發(fā)劑吸收UV光產(chǎn)生活性自由基觸發(fā)聚合反應(yīng),包括鏈引發(fā)、增長(zhǎng)、終止和交聯(lián)。反應(yīng)速率受UV光強(qiáng)、光引發(fā)劑濃度、單體類型等因素影響,UV固化技術(shù)具有快速固化特性。
    的頭像 發(fā)表于 12-06 09:33 ?772次閱讀

    盤點(diǎn)Linux系統(tǒng)中的常見(jiàn)命令

    作為運(yùn)維同學(xué)怎能不知道Linux系統(tǒng)中的lsmod、lsof、lspci、lsscsi命令呢,今天就來(lái)盤一盤她及實(shí)例。
    的頭像 發(fā)表于 12-03 09:48 ?726次閱讀
    盤點(diǎn)Linux系統(tǒng)中的常見(jiàn)命令

    關(guān)于陶瓷電路板不知道的事

    陶瓷電路板(Ceramic Circuit Board),又稱陶瓷基板,是一種以陶瓷材料為基體,通過(guò)精密的制造工藝在表面形成電路圖形的高技術(shù)產(chǎn)品,快來(lái)看看哪些是您還不知道的事?
    的頭像 發(fā)表于 10-21 11:55 ?895次閱讀
    <b class='flag-5'>關(guān)于</b>陶瓷電路板<b class='flag-5'>你</b><b class='flag-5'>不知道</b>的事

    又一電工不知道,施耐德變頻器怎么復(fù)位,如果不告訴知道怎么復(fù)位嗎?

    維修 我給他說(shuō),可能以前沒(méi)接觸過(guò)施耐德的變頻器,就不知道它還有一個(gè)蓋子,要復(fù)位的話,就要把蓋子打開(kāi),第一次找不到也正常,要是經(jīng)常斷電重啟的話,對(duì)設(shè)備不好。 變頻器修理 之所以分享給大家,就是想告訴那些沒(méi)接觸過(guò)施耐
    的頭像 發(fā)表于 10-12 15:15 ?1003次閱讀
    又一電工<b class='flag-5'>不知道</b>,施耐德變頻器怎么復(fù)位,如果不告訴<b class='flag-5'>你</b>,<b class='flag-5'>你</b><b class='flag-5'>知道</b>怎么復(fù)位嗎?

    使用CS1232 采集一個(gè)小信號(hào),信號(hào)有可能是正,也可能是負(fù) ,是不知道怎么回事情?

    我使用CS1232 采集一個(gè)小信號(hào),信號(hào)有可能是正,也可能是負(fù) 但是不知道怎么回事情,采集的數(shù)據(jù)就經(jīng)常不對(duì) 在上圖的電路中,當(dāng)我把P4 短路,采集到的電壓盡然是為8388608 我看了一下SDO
    發(fā)表于 09-25 14:36

    知道貼片電感故障時(shí)可能出現(xiàn)的癥狀嗎?

    知道貼片電感故障時(shí)可能出現(xiàn)的癥狀嗎?
    的頭像 發(fā)表于 08-17 14:20 ?719次閱讀
    <b class='flag-5'>你</b><b class='flag-5'>知道</b>貼片電感故障時(shí)<b class='flag-5'>可能</b>出現(xiàn)的癥狀嗎?

    AMC1100使用前需要烘烤,不知道烘烤溫度和烘烤時(shí)間是多少?

    1:AMC1100使用前需要烘烤,但是不知道 烘烤溫度和烘烤時(shí)間是多少?能在datasheet上查看到嗎? 2:datasheet上 MSL參數(shù) Level-1-260C-UNLIM中UNLIM
    發(fā)表于 08-09 08:11

    新手嘗試做一個(gè)LED驅(qū)動(dòng)電路,不知道電路有沒(méi)有問(wèn)題

    TP8006穩(wěn)流驅(qū)動(dòng),最后留出LED插口。 因?yàn)椴皇呛芏布O(shè)計(jì),不知道做的模塊能不能行,很希望各位提提意見(jiàn),讓我認(rèn)識(shí)認(rèn)識(shí)硬件設(shè)計(jì)上的缺陷。
    發(fā)表于 07-24 18:35

    不知道怎么進(jìn)行負(fù)載測(cè)試發(fā)電機(jī)嗎?

    測(cè)試一般的流程是怎樣的,知道嗎? ? 1、試驗(yàn)前準(zhǔn)備:確保發(fā)電機(jī)和試驗(yàn)設(shè)備處于良好的工作狀態(tài),檢查發(fā)電機(jī)的電源和燃料供應(yīng)是否正常,確保試驗(yàn)設(shè)備與發(fā)電機(jī)的連接正確可靠。 2、確定試驗(yàn)載荷:根據(jù)您的實(shí)際要求確定試驗(yàn)
    的頭像 發(fā)表于 07-03 17:36 ?1534次閱讀
    主站蜘蛛池模板: 久久精品国产免费高清 | 97影院3| 一区在线播放 | 免费观看午夜在线欧差毛片 | 天天干天天操天天拍 | 亚洲免费在线观看 | 人操人摸 | 成年色黄大色黄大片 视频 成年视频xxxxx免费播放软件 | 日本.www| 午夜高清在线观看免费6 | 久久久久久毛片免费播放 | 日韩毛片网站 | 女人张开腿让男人桶视频免费大全 | 午夜国产福利 | 黄色片网站日本 | 4455四色永久免费 | 黄色欧美 | freesex性| 美女视频黄a全部免费看小说 | 久久成人福利视频 | 激情六月丁香婷婷 | 天堂在线天堂最新版在线www | 天天弄 | 亚洲理论视频 | 国产精品一区二区三区免费视频 | 中国业余老太性视频 | 婷婷九月色 | 天天摸日日添狠狠添婷婷 | 极品美女啪啪 | 美女黄频 | 高h办公室 | 亚洲成人综合网站 | 精品国产午夜久久久久九九 | 全黄性色大片 | www.av在线免费观看 | 欧美色综合高清视频在线 | 狠狠做深爱婷婷久久一区 | 操爽视频 | 亚洲日本免费 | 国产成人三级 | 男人的午夜影院 |