精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

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

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

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

【C語(yǔ)言進(jìn)階】sprintf和snprintf的區(qū)別

嵌入式物聯(lián)網(wǎng)開(kāi)發(fā) ? 來(lái)源:嵌入式物聯(lián)網(wǎng)開(kāi)發(fā) ? 作者:嵌入式物聯(lián)網(wǎng)開(kāi)發(fā) ? 2022-08-31 13:18 ? 次閱讀

C語(yǔ)言上總有些非常相近的接口函數(shù),比如sprintf和snprintf就是其中的一對(duì)。以筆者多年的工作經(jīng)驗(yàn),這對(duì)接口函數(shù)在平時(shí)的編程中,使用的頻度是非常高,只是你真的了解它們倆的區(qū)別嗎?

帶著這個(gè)問(wèn)題,請(qǐng)跟隨筆者的思路梳理一遍sprintf和snprintf。通過(guò)閱讀本文,你將了解到以下內(nèi)容:

sprintf和snpintf分別是什么?

sprintf和snprintf的區(qū)別與聯(lián)系

sprintf和snprintf的使用秘訣


sprintf和snpintf分別是什么?


【sprintf】的函數(shù)原型如下所示:

/**
功能: 把格式化的數(shù)據(jù)寫(xiě)入某個(gè)字符串緩沖區(qū)
入?yún)ⅲ篺ormat,輸出字符串的格式化列表,比如"%s %d %c"等
入?yún)? [argument],format對(duì)應(yīng)的不定參數(shù)列表,與printf的不定入?yún)㈩愃?出參:buffer,指向一段存儲(chǔ)空間,用于存儲(chǔ)格式化之后的字符串
返回值:返回寫(xiě)入buffer 的字符數(shù),出錯(cuò)則返回-1. 如果 buffer 或 format 是空指針,
且不出錯(cuò)而繼續(xù),函數(shù)將返回-1,并且 errno 會(huì)被設(shè)置為 EINVAL。
備注:它是個(gè)變參函數(shù)
*/
int sprintf( char *buffer, const char *format, [ argument] … );

【snprintf】的函數(shù)原型如下所示:

/**
功能: 有長(zhǎng)度限制地,把格式化的數(shù)據(jù)寫(xiě)入某個(gè)字符串緩沖區(qū)
入?yún)ⅲ篺ormat,輸出字符串的格式化列表,比如"%s %d %c"等
入?yún)? [argument],format對(duì)應(yīng)的不定參數(shù)列表,與printf的不定入?yún)㈩愃?入?yún)ⅲ簊ize,表示buffer指向存儲(chǔ)空間的大小
出參:buffer,指向一段存儲(chǔ)空間,用于存儲(chǔ)格式化之后的字符串
返回值:返回寫(xiě)入buffer 的字符數(shù),出錯(cuò)則返回-1. 如果 buffer 或 format 是空指針,
且不出錯(cuò)而繼續(xù),函數(shù)將返回-1,并且 errno 會(huì)被設(shè)置為 EINVAL。
備注:它是個(gè)變參函數(shù)
*/
int snprintf( char *buffer, size_t size, const char *format, [ argument] … );

sprintf和snprintf的區(qū)別與聯(lián)系


通過(guò)對(duì)比sprintf和snprintf的函數(shù)原型,我們可以發(fā)現(xiàn)兩者其實(shí)完成相同功能的接口,都是將一段數(shù)據(jù)經(jīng)格式化操作之后,轉(zhuǎn)換成一段字符串,通過(guò)接口傳入的buffer指針將格式化的字符串內(nèi)容輸出。

我們細(xì)細(xì)比對(duì)兩個(gè)函數(shù)原型,我們會(huì)發(fā)現(xiàn)snprintf比sprintf多了一個(gè)表示buffer指針指向存儲(chǔ)空間的大小的入?yún)ize,那么它到底有什么作用呢?我們先來(lái)分析下snprintf接口的內(nèi)部行為與size的關(guān)系:

如果格式化后的字符串長(zhǎng)度 < size,則將此字符串全部復(fù)制到str中,并給其后添加一個(gè)字符串結(jié)束符('\0')

如果格式化后的字符串長(zhǎng)度 >= size,則只將其中的(size-1)個(gè)字符復(fù)制到str中,并給其后添加一個(gè)字符串結(jié)束符('\0'),返回值為欲寫(xiě)入的字符串長(zhǎng)度。

看完這一段解釋之后,大概你就明白了,原來(lái)snprintf就是sprintf的安全版本,因?yàn)閱螐膕printf的內(nèi)部行為來(lái)看,它是沒(méi)有辦法保證對(duì)buffer指針的賦值操作是沒(méi)有越界的,因?yàn)樗鼔焊筒恢纀uffer的存儲(chǔ)空間多少有多大,所以它只能認(rèn)為是【無(wú)窮大】。但是snprintf通過(guò)入?yún)ize,恰好可以很好的解決這個(gè)問(wèn)題,它可以很明確的告知snprintf的內(nèi)部操作,以size作為界線,當(dāng)輸出的字符串長(zhǎng)度要超過(guò)size時(shí),應(yīng)做出裁剪輸出。在很多的編程寶典中,都是推薦使用snprintf,而要求編程者盡可能地避免使用sprintf這種不安全接口。


sprintf和snprintf的使用秘訣


我們通過(guò)一段測(cè)試代碼來(lái)展示下兩者的使用方法,以及上一小結(jié)中提及的可能導(dǎo)致buffer溢出的嚴(yán)重問(wèn)題:

//sprintf的用法
{
    char buffer[10]; //定義一個(gè)只有10個(gè)字節(jié)空間的buffer數(shù)組
    const int a = 12345; //定義一個(gè)int型的常量
    const char *msg = "012345678901234567890"; //定義一個(gè)長(zhǎng)度為20字節(jié)的字符串常量

    sprintf(buffer, "%d", a); //將a變量按int類型打印成字符串,輸出到buffer中
    /*
    輸出分析:
    輸出結(jié)果: buffer="12345"
    因?yàn)樽詈筝敵龅腷uffer內(nèi)容長(zhǎng)度不超過(guò)10字節(jié),所以此時(shí)sprintf操作是沒(méi)有溢出風(fēng)險(xiǎn)的
    */

    sprintf(buffer, "%d+%s", a, msg); //將a變量和msg字符串通過(guò)“+”連接成一個(gè)字符串
    /*
    輸出分析:
    由于buffer只有10個(gè)字節(jié)空間,而sprintf在執(zhí)行字符串格式化輸出的時(shí),并不知道buffer的真實(shí)長(zhǎng)度,
    所以它會(huì)將"12345+012345678901234567890"這整個(gè)字符串都拷貝到buffer空間上,這就導(dǎo)致了buffer存儲(chǔ)空間溢出了。
    從存儲(chǔ)位置上分析,我們知道buffer空間屬于一個(gè)棧空間,在它自己的10字節(jié)之外的空間很明顯是其他棧變量的存儲(chǔ)空間,
    一旦sprintf將10字節(jié)外的其他空間也操作了,這就有可能破壞了其他棧變量的內(nèi)容,這有可能是致命的。
    */
}

//snprintf的用法
{
    char buffer[10]; //定義一個(gè)只有10個(gè)字節(jié)空間的buffer數(shù)組
    const int a = 12345; //定義一個(gè)int型的常量
    const char *msg = "012345678901234567890"; //定義一個(gè)長(zhǎng)度為20字節(jié)的字符串常量

    snprintf(buffer, sizeof(buffer), "%d", a); //將a變量按int類型打印成字符串,輸出到buffer中
    /*
    輸出分析:
    輸出結(jié)果: buffer="12345"
    因?yàn)樽詈筝敵龅腷uffer內(nèi)容長(zhǎng)度不超過(guò)10字節(jié),所以snprintf操作是沒(méi)有溢出風(fēng)險(xiǎn)的;
    此種情況下,使用sprintf和snpintf都可以得到同樣的結(jié)果,且都不會(huì)產(chǎn)生數(shù)組溢出。
    */

    sprintf(buffer, sizeof(buffer), "%d+%s", a, msg); //將a變量和msg字符串通過(guò)“+”連接成一個(gè)字符串
    /*
    輸出分析:
    輸出結(jié)果是: buffer="12345+0123",加上一個(gè)'\0'的字符串結(jié)束符,
    剛好占用了buffer的10字節(jié)的存儲(chǔ)空間,不存在任何的buffer溢出風(fēng)險(xiǎn)。而"0123"后面的字符串都被snprintf內(nèi)部裁剪掉了,這就體現(xiàn)了snprintf操作安全的特性。
    */
}

通過(guò)以上分析,我們很好地認(rèn)識(shí)到了sprintf的操作是不安全的。在C語(yǔ)言的語(yǔ)法上,指針的靈活性也帶來(lái)可能導(dǎo)致的指針溢出風(fēng)險(xiǎn),而snprintf恰好就是解決了這個(gè)困惑的sprintf升級(jí)版本。

類似的,還有strcat和strncat、strcpy和strncpy等等。通過(guò)本文的方法,讀者也可以寫(xiě)一小段測(cè)試代碼,好好捋一捋本文提及的這幾組函數(shù),一起領(lǐng)悟下其他的奧秘和使用風(fēng)險(xiǎn)吧。

以上總結(jié),均來(lái)自筆者多年的實(shí)踐經(jīng)驗(yàn),如有發(fā)現(xiàn)不正確的陳述或錯(cuò)誤的觀點(diǎn),還望讀者指正,感激不盡。

審核編輯:湯梓紅
聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(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)投訴
  • C語(yǔ)言
    +關(guān)注

    關(guān)注

    180

    文章

    7598

    瀏覽量

    136197
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4306

    瀏覽量

    62430
  • sprintf
    +關(guān)注

    關(guān)注

    0

    文章

    6

    瀏覽量

    4012
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    C語(yǔ)言進(jìn)階】面試題:請(qǐng)使用宏定義實(shí)現(xiàn)字節(jié)對(duì)齊

    C語(yǔ)言進(jìn)階】面試題:請(qǐng)使用宏定義實(shí)現(xiàn)字節(jié)對(duì)齊
    的頭像 發(fā)表于 07-11 09:21 ?2751次閱讀
    【<b class='flag-5'>C</b><b class='flag-5'>語(yǔ)言</b><b class='flag-5'>進(jìn)階</b>】面試題:請(qǐng)使用宏定義實(shí)現(xiàn)字節(jié)對(duì)齊

    嵌入式C語(yǔ)言進(jìn)階之道

    嵌入式C語(yǔ)言進(jìn)階之道
    發(fā)表于 08-20 16:02

    c語(yǔ)言之高手進(jìn)階

    c語(yǔ)言之高手進(jìn)階 從點(diǎn)滴開(kāi)始 楊帆起航
    發(fā)表于 07-04 16:14

    C語(yǔ)言進(jìn)階

    C語(yǔ)言進(jìn)階見(jiàn)附件
    發(fā)表于 08-13 15:51

    C語(yǔ)言進(jìn)階書(shū)分享!

    挺好的。c語(yǔ)言進(jìn)階.pdf (1.78 MB )
    發(fā)表于 10-16 02:44

    sprintf與printf函數(shù)的區(qū)別

    單片機(jī)中Sprint函數(shù):說(shuō)明1:使用該函數(shù)時(shí)必須包含stdio.h頭文件,否則容易卡死程序說(shuō)明2:sprintf與printf函數(shù)的區(qū)別:二者功能相似,但是sprintf函數(shù)打印到字符串中(將數(shù)值
    發(fā)表于 08-23 06:18

    單片機(jī)IO擴(kuò)展(進(jìn)階)程序集合【C語(yǔ)言

    單片機(jī)IO擴(kuò)展(進(jìn)階)程序集合【C語(yǔ)言】。
    發(fā)表于 01-06 11:04 ?23次下載

    sprintf和printf的區(qū)別

    的變量,最終函數(shù)就會(huì)用相應(yīng)位置的變量來(lái)替代那個(gè)說(shuō)明符,產(chǎn)生一個(gè)調(diào)用者想要的字符串。那么接下來(lái)我們一起了解一下sprintf與printf的區(qū)別
    發(fā)表于 11-28 14:41 ?1.7w次閱讀

    C51單片機(jī)C語(yǔ)言與標(biāo)準(zhǔn)C語(yǔ)言有什么區(qū)別

    一:C51(單片機(jī)C語(yǔ)言)與標(biāo)準(zhǔn)C語(yǔ)言區(qū)別1、 C
    發(fā)表于 10-09 08:00 ?134次下載
    <b class='flag-5'>C</b>51單片機(jī)<b class='flag-5'>C</b><b class='flag-5'>語(yǔ)言</b>與標(biāo)準(zhǔn)<b class='flag-5'>C</b><b class='flag-5'>語(yǔ)言</b>有什么<b class='flag-5'>區(qū)別</b>?

    C語(yǔ)言進(jìn)階學(xué)習(xí)課件資料合集

    本文檔的主要內(nèi)容詳細(xì)介紹的是C語(yǔ)言進(jìn)階學(xué)習(xí)課件資料合集包括了:第1節(jié)-數(shù)據(jù)的存儲(chǔ),第2節(jié)-指針的進(jìn)階,第3節(jié)-字符串+內(nèi)存函數(shù)的介紹,第4節(jié)-自定義類型詳解(結(jié)構(gòu)體+枚舉+聯(lián)合),第
    發(fā)表于 07-14 08:00 ?11次下載
    <b class='flag-5'>C</b><b class='flag-5'>語(yǔ)言</b>的<b class='flag-5'>進(jìn)階</b>學(xué)習(xí)課件資料合集

    C語(yǔ)言進(jìn)階】“數(shù)組指針”和“指針數(shù)組”都是啥跟啥?

    C語(yǔ)言進(jìn)階】“數(shù)組指針”和“指針數(shù)組”都是啥跟啥?
    的頭像 發(fā)表于 08-31 13:21 ?1885次閱讀

    C語(yǔ)言進(jìn)階C語(yǔ)言指針的高階用法

    C語(yǔ)言進(jìn)階C語(yǔ)言指針的高階用法
    的頭像 發(fā)表于 08-31 13:24 ?2282次閱讀

    C語(yǔ)言進(jìn)階】利用assert高效排查你的C程序

    C語(yǔ)言進(jìn)階】利用assert高效排查你的C程序
    的頭像 發(fā)表于 08-31 13:27 ?2076次閱讀

    C語(yǔ)言進(jìn)階之嵌入式系統(tǒng)高級(jí)C語(yǔ)言編程

    電子發(fā)燒友網(wǎng)站提供《C語(yǔ)言進(jìn)階之嵌入式系統(tǒng)高級(jí)C語(yǔ)言編程.rar》資料免費(fèi)下載
    發(fā)表于 11-18 10:32 ?1次下載
    <b class='flag-5'>C</b><b class='flag-5'>語(yǔ)言</b><b class='flag-5'>進(jìn)階</b>之嵌入式系統(tǒng)高級(jí)<b class='flag-5'>C</b><b class='flag-5'>語(yǔ)言</b>編程

    PLC編程語(yǔ)言C語(yǔ)言區(qū)別

    在工業(yè)自動(dòng)化和計(jì)算機(jī)編程領(lǐng)域中,PLC(可編程邏輯控制器)編程語(yǔ)言C語(yǔ)言各自扮演著重要的角色。盡管兩者都是編程語(yǔ)言,但它們?cè)诙鄠€(gè)方面存在顯著的區(qū)別
    的頭像 發(fā)表于 06-14 17:11 ?2529次閱讀