Calvin's Tech Space

          成于堅(jiān)忍,毀于浮躁

             :: 首頁 :: 聯(lián)系 :: 聚合  :: 管理
          http://hi.baidu.com/liziyun537/blog/item/ae84671a6a75e9d9ac6e754e.html

          關(guān)于sprintf和snprintf的正確使用

          考慮以下有缺陷的例子:
          void f(const char *p)
          {
          char buf[11]={0};
          sprintf(buf,"%10s",p); // very dangerous
          printf("%sn",buf);
          }

          不要讓格式標(biāo)記“%10s”誤導(dǎo)你。如果p的長度大于10個(gè)字符,那么 sprintf() 的寫操作就會(huì)越過buf的邊界,從而產(chǎn)生一個(gè)緩沖區(qū)溢出。
          檢測(cè)這類缺陷并不容易,因?yàn)樗鼈冎辉?p 的長度大于10個(gè)字符的時(shí)候才會(huì)發(fā)生。黑客通常利用這類脆弱的代碼來入侵看上去安全的系統(tǒng)。

          要修正這一缺陷,可以使用函數(shù) snprintf()代替函數(shù)sprintf()

          函數(shù)原型:int snprintf(char *dest, size_t n, const char *fmt, ...);
          函數(shù)說明: 最多從源串中拷貝n-1個(gè)字符到目標(biāo)串中,然后再在后面加一個(gè)0。所以如果目標(biāo)串的大小為n的話,將不會(huì)溢出。
          函數(shù)返回值: 若成功則返回存入數(shù)組的字符數(shù),若編碼出錯(cuò)則返回負(fù)值。

          推薦的用法:
          void f(const char *p)
          {
          char buf[11]={0};
          snprintf(buf, sizeof(buf), "%10s", p); // 注意:這里第2個(gè)參數(shù)應(yīng)當(dāng)用sizeof(str),而不要使用硬編碼11,也不應(yīng)當(dāng)使用sizeof(str)-1或10
          printf("%sn",buf);
          }

          strcpy 函數(shù)操作的對(duì)象是 字符串,完成 從 源字符串 到 目的字符串 的 拷貝 功能。

          snprintf 函數(shù)操作的對(duì)象 不限于字符串:雖然目的對(duì)象是字符串,但是源對(duì)象可以是字符串、也可以是任意基本類型的數(shù)據(jù)。這個(gè)函數(shù)主要用來實(shí)現(xiàn) (字符串或基本數(shù)據(jù)類型)向 字符串 的轉(zhuǎn)換功能。如果源對(duì)象是字符串,并且指定 %s 格式符,也可實(shí)現(xiàn)字符串拷貝功能。

          memcpy 函數(shù)顧名思義就是 內(nèi)存拷貝,實(shí)現(xiàn) 將一個(gè) 內(nèi)存塊 的內(nèi)容復(fù)制到另一個(gè) 內(nèi)存塊 這一功能。內(nèi)存塊由其首地址以及長度確定。程序中出現(xiàn)的實(shí)體對(duì)象,不論是什么類型,其最終表現(xiàn)就是在內(nèi)存中占據(jù)一席之地(一個(gè)內(nèi)存區(qū)間或塊)。因此,memcpy 的操作對(duì)象不局限于某一類數(shù)據(jù)類型,或者說可 適用于任意數(shù)據(jù)類型,只要能給出對(duì)象的起始地址和內(nèi)存長度信息、并且對(duì)象具有可操作性即可。鑒于 memcpy 函數(shù)等長拷貝的特點(diǎn)以及數(shù)據(jù)類型代表的物理意義,memcpy 函數(shù)通常限于同種類型數(shù)據(jù)或?qū)ο笾g的拷貝,其中當(dāng)然也包括字符串拷貝以及基本數(shù)據(jù)類型的拷貝。

          對(duì)于字符串拷貝來說,用上述三個(gè)函數(shù)都可以實(shí)現(xiàn),但是其實(shí)現(xiàn)的效率和使用的方便程度不同:
          • strcpy 無疑是最合適的選擇:效率高且調(diào)用方便。
          • snprintf 要額外指定格式符并且進(jìn)行格式轉(zhuǎn)化,麻煩且效率不高。
          • memcpy 雖然高效,但是需要額外提供拷貝的內(nèi)存長度這一參數(shù),易錯(cuò)且使用不便;并且如果長度指定過大的話(最優(yōu)長度是源字符串長度 + 1),還會(huì)帶來性能的下降。其實(shí) strcpy 函數(shù)一般是在內(nèi)部調(diào)用 memcpy 函數(shù)或者用匯編直接實(shí)現(xiàn)的,以達(dá)到高效的目的。因此,使用 memcpy 和 strcpy 拷貝字符串在性能上應(yīng)該沒有什么大的差別。

          對(duì)于非字符串類型的數(shù)據(jù)的復(fù)制來說,strcpy 和 snprintf 一般就無能為力了,可是對(duì) memcpy 卻沒有什么影響。但是,對(duì)于基本數(shù)據(jù)類型來說,盡管可以用 memcpy 進(jìn)行拷貝,由于有賦值運(yùn)算符可以方便且高效地進(jìn)行同種或兼容類型的數(shù)據(jù)之間的拷貝,所以這種情況下 memcpy 幾乎不被使用。memcpy 的長處是用來實(shí)現(xiàn)(通常是內(nèi)部實(shí)現(xiàn)居多)對(duì)結(jié)構(gòu)或者數(shù)組的拷貝,其目的是或者高效,或者使用方便,甚或兩者兼有。

          strcpy和memcpy功能上也有些差別:
          比如:
          const char *str1="abc\0def";
          char str2[7];

          首先用strcpy實(shí)現(xiàn):
          strcpy(str2,str1)
          得到結(jié)果:str2="abc";也就是說,strcpy是以'\0'為結(jié)束標(biāo)志的。

          再用memcpy實(shí)現(xiàn):
          memset(str2,7);
          memcpy(str2,str1,7);
          得到結(jié)果:str2="abc\0def";
          也就是說,memcpy是對(duì)內(nèi)存區(qū)域的復(fù)制。當(dāng)然,不僅能夠復(fù)制字符串?dāng)?shù)組,而且能夠復(fù)制整型數(shù)組等其他數(shù)組。
          posted on 2011-09-11 14:45 calvin 閱讀(1526) 評(píng)論(0)  編輯  收藏 所屬分類: C
          主站蜘蛛池模板: 武鸣县| 南通市| 固镇县| 万盛区| 安顺市| 雷山县| 桃园市| 西乌珠穆沁旗| 那坡县| 宁阳县| 枣庄市| 孝昌县| 兴宁市| 天祝| 青海省| 望城县| 永昌县| 五寨县| 枣强县| 德阳市| 平乐县| 大安市| 潞城市| 腾冲县| 安乡县| 庆阳市| 灌云县| 北海市| 邯郸市| 阳谷县| 古交市| 乐昌市| 翼城县| 浠水县| 梁平县| 察雅县| 鲁甸县| 江安县| 公安县| 兴业县| 梁河县|