iT邦幫忙

DAY 16
0

21世紀C語言實作及感想系列 第 16

21世紀C語言之16 :用asprintf來改善sprintf

  • 分享至 

  • xImage
  •  

如果讀者不知道sprintf, snprintf, asprintf, 可以google一下,因為他們不是把字串打印到畫面,而是功能少一點,只有格式化,而常見的printf, fprintf, 格式化字串後還會輸出到畫面。

它一開頭給的兩個例子不是很好,筆者也不是看得很懂,可以參考這篇文章

http://kheresy.wordpress.com/2010/01/28/%E7%94%A8-snprintf-asprintf-%E5%8F%96%E4%BB%A3%E4%B8%8D%E5%AE%89%E5%85%A8%E7%9A%84-sprintf/

我實作了一下

#define _GNU_SOURCE //cause stdio.h to include asprintf
#include <stdio.h>
int main() { 

int tmp = 10000; //100
char *cstr;//[20];
//sprintf(cstr, "%d * %d = %d", tmp, tmp, tmp * tmp );
//snprintf(cstr,sizeof(cstr), "%d * %d = %d", tmp, tmp, tmp * tmp );

asprintf(&cstr, "%d * %d = %d", tmp, tmp, tmp * tmp );
printf("%s \n", cstr);
}






傳統的sprintf,函數有個缺點,就是有 
buffer overflow的問題,

一開始,當tmp =100 時,輸出10 * 10 = 100,但是tmp=10000. 就

*** buffer overflow detected ***: ./sprf terminated
======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6(__fortify_fail+0x63)[0xb76b17b3]

以下省略,

這時候,C99 就新增了snprintf, 比sprintf 多了一個參數,字串長度

sizeof(cstr),這樣就不會buffer overflow,可是又帶來了一個問題,

上面程式的輸出結果為

10000 * 10000 = 100

snprintf是給多少長度,就印出多長的字。

而GNU C Library的維護者,又發明asprintf來改善sprintf,

乾脆連長度也不用指定了,幫你分配長度。


而asprintf 做了兩件事,

作者寫了比對,

老式寫法,

int len = strlen("strings ") + strlen(in) + 1;
cmd = malloc(len);
snprintf(cmd, len, "strings %s", in);

新式寫法,

asprintf(&cmd, "strings %s", in);

只是引進了asprintf,仍然有安全性的問題,因為不限長度,還是有可能遇到記憶体不足。還不如snprintf。

所以作者又編了一個巨集,來防止這個情況,

Stopif(asprintf(&str, "%s", user_input)==-1, return -1, "asprintf failed.")

弄了一段時間,開始覺得C語言的細節非常多。

再來是

Constant Strings 的問題,

#include <stdio.h>
int main(){
char *s1 = "Thread";
char *s2;
asprintf(&s2, "Floss");

printf("%s\n", s1);
printf("%s\n", s2);
//s2[0]='f'; //Switch Floss to lowercase.
//s1[0]='t'; //Segfault.
free(s2); //Clean up.
free(s1); //Segfault.
}

這時的

asprintf 變成一個可變換字元的複製函數,

程式中的s2不會當掉,而s1會

程式記憶體區段錯誤 (core dumped)

*** Error in `./strdup': munmap_chunk(): invalid pointer: 0x08048566 ***
======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6(+0x767c2)[0xb76357c2]

想一想以往高階語言的觀念,好像沒有char的觀念,用mid, left, substr, right來替換字串裏的字元,在C語言就要小心。

編譯時,聰明的編譯器會告訴你

strdup.c:12:5: warning: attempt to free a non-heap object [-Wfree-nonheap-object]

一個簡單的宣告,背後藏著一些秘密。


上一篇
21世紀C語言之15 :巨集的困惑
下一篇
21世紀C語言之17 : __VA_ARGS__和...和args...和##
系列文
21世紀C語言實作及感想30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言