日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

各种输出函数的比较(printf/fprintf/sprintf/snprintf/vprintf/vfprintf/vsprintf/vsnprintf)

發(fā)布時(shí)間:2023/12/15 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 各种输出函数的比较(printf/fprintf/sprintf/snprintf/vprintf/vfprintf/vsprintf/vsnprintf) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

對于程序猿來說,printf函數(shù)可以說是最熟悉的一個(gè)工具了。利用它可以將各類調(diào)試信息輸出到指定的設(shè)備(比如串口)中,實(shí)現(xiàn)對程序運(yùn)行狀態(tài)的掌控和分析。不過,在實(shí)際的應(yīng)用中,相信大家除了printf函數(shù)之外,應(yīng)該還見過幾個(gè)與其類似的函數(shù),包括fprintf、sprintf、snprintf、vprintf、vfprintf、vsprintf、vsnprintf等等。那么,這些看上去很類似的函數(shù)之間,到底有什么區(qū)別,各自的作用到底是什么?今天就來總結(jié)一下。

首先列出全部的函數(shù)申明,以供參考。

#include <stdio.h>int printf(const char *format, ...); int fprintf(FILE *stream, const char *format, ...); int sprintf(char *str, const char *format, ...); int snprintf(char *str, size_t size, const char *format, ...);#include <stdarg.h>int vprintf(const char *format, va_list ap); int vfprintf(FILE *stream, const char *format, va_list ap); int vsprintf(char *str, const char *format, va_list ap); int vsnprintf(char *str, size_t size, const char *format, va_list ap);

怎么樣,是不是看的有點(diǎn)暈?沒關(guān)系,我們可以先用一個(gè)表格來大致區(qū)分一下上述這些函數(shù)的異同點(diǎn),就不會(huì)那么暈了。

參數(shù)類型輸出到設(shè)備輸出到文件輸出到字符串
可變參數(shù)printffprintfsprintf、snprintf
固定參數(shù)vprintfvfprintfvsprintf、vsnprintf

OK,下面我們就來逐個(gè)進(jìn)行詳細(xì)的介紹和比對。

一、printf和vprintf

多數(shù)情況下使用printf() 。只有當(dāng)你需要自己寫一個(gè)printf()那樣的專有函數(shù)的時(shí)候才需要vprintf()。比如你寫一個(gè)自己專門的錯(cuò)誤輸出函數(shù):

int error(char *fmt, ...) {int result;va_list args;va_start(args, fmt);// 一些內(nèi)容va_end(args);return result; }

應(yīng)當(dāng)注意到,你不能轉(zhuǎn)發(fā)參數(shù)給printf,因?yàn)閜rintf是變長參數(shù)的,而不是vprintf的單獨(dú)一個(gè)va_list。然而vprintf() 函數(shù), 只取一個(gè)合并的va_list 參數(shù), 所以完整的版本是:

int error(char *fmt, ...) {int result;va_list args;va_start(args, fmt);fputs("Error: ", stderr);result = vfprintf(stderr, fmt, args);va_end(args);return result; }

二、fprintf和vfprintf

兩個(gè)函數(shù)從聲明看,第三個(gè)參數(shù)有區(qū)別,這樣就形成了兩個(gè)函數(shù)不同的作用。比如,你要寫一個(gè)日志函數(shù):

void log(FILE *file, const char* format, ... ) {va_list args;va_start (args, format);fprintf(file, "%s: ", getTimestamp());vfprintf (file, format, args); //在這個(gè)地方用vfprintf函數(shù)就很合適,因?yàn)榈谌齻€(gè)參數(shù)可以直接得到va_end (args); }

vfprintf適合參數(shù)可變列表傳遞。

三、sprintf和vsprintf

先看一個(gè)例子:

#include <stdio.h> #include <stdafx.h>int _tmain(int argc, _TCHAR* argv[]) {char *p1="China";char a[20];sprintf(a,"%s",p1);printf("%s\n",a);memset(a,0,sizeof(a));snprintf(a,3,"%s",p1);printf("%s\n",a);printf("%d\n",strlen(a));return 0; }

結(jié)果輸出:

China
Chi
3

過程分析:
sprintf(a,”%s”,p1) 把p1字符串拷貝到數(shù)組a中(‘\0’也拷貝過去了)。
snprintf(a,3,”%s”,p1) 拷貝P1中前3個(gè)字符到數(shù)組a中,并在末尾自動(dòng)添加’\0’。

sprintf屬于I/O庫函數(shù),snprintf函數(shù)并不是標(biāo)準(zhǔn)c/c++中規(guī)定的函數(shù),但是在許多編譯器中,廠商提供了其實(shí)現(xiàn)的版本。在gcc中,該函數(shù)名稱就snprintf,而在VC中稱為_snprintf。 如果你在VC中使用snprintf(),會(huì)提示此函數(shù)未聲明,改成_snprintf()即可。

注意點(diǎn):
1 sprintf是一個(gè)不安全函數(shù),src串的長度應(yīng)該小于dest緩沖區(qū)的大小,(如果src串的長度大于或等于dest緩沖區(qū)的大小,將會(huì)出現(xiàn)內(nèi)存溢出。)
2 snprintf中源串長度應(yīng)該小于目標(biāo)dest緩沖區(qū)的大小,且size等于目標(biāo)dest緩沖區(qū)的大小。(如果源串長度大于或等于目標(biāo)dest緩沖區(qū)的大小,且size等于目標(biāo)dest緩沖區(qū)的大小,則只會(huì)拷貝目標(biāo)dest緩沖區(qū)的大小減1個(gè)字符,后加’\0’;該情況下,如果size大于目標(biāo)dest緩沖區(qū)的大小則溢出。)
3 snprintf ()函數(shù)返回值問題, 如果輸出因?yàn)閟ize的限制而被截?cái)?#xff0c;返回值將是“如果有足夠空間存儲(chǔ),所應(yīng)能輸出的字符數(shù)(不包括字符串結(jié)尾的’\0’)”,這個(gè)值和size相等或者比size大!也就是說,如果可以寫入的字符串是”0123456789ABCDEF”共16位,但是size限制了是10,這樣 snprintf() 的返回值將會(huì)是16 而不是10!

四、snprintf和vsnprintf

同樣來看一個(gè)例子:

#include <iostream> #include <cstring> #define snprintf _snprintf using namespace std; int main() { char str[10] = {0}; char *data = "abcdefg"; sprintf(str, "debug : %s", data); cout << str << endl; return 0; }

該程序可以編譯過,但是在運(yùn)行期間會(huì)崩潰,原因相信大家都能看的出來。那么,應(yīng)該如何處理呢?

#include <iostream> #include <cstring> #define snprintf _snprintf using namespace std; int main() { char str[10] = {0}; char *data = "abcdefg"; snprintf(str, sizeof(str) - 1, "debug : %s", data); cout << str << endl; return 0; }

這樣就安全了,和strncpy非常類似。

另外,需要特別注意的是: Windows和Linux中的snprintf函數(shù)有區(qū)別, 在linux代碼中,經(jīng)常見到snprintf(str, sizeof(str), “…”)這樣的用法, 為什么這里不是sizof(str) - 1呢?

我們看看Windows下這么用會(huì)怎樣:

#include <iostream> #include <cstring> #define snprintf _snprintf using namespace std; int main() { char str[10] = {0}; char *data = "abcdefgddddddddddddddddddddd"; snprintf(str, sizeof(str), "debug : %s", data); cout << str << endl; return 0; }

我運(yùn)行的時(shí)候,程序沒有崩潰,算是萬幸。 但結(jié)果亂碼??磥?#xff0c;沒有自動(dòng)在str最后加’\0’, 在linux中, 就安全了, 會(huì)自動(dòng)補(bǔ)哈, 所以永遠(yuǎn)不會(huì)越界。

總結(jié)一下:
1. Linux中, 對于snprintf, 用sizeof(str), 最后會(huì)自動(dòng)加’\0’, 比strncpy更安全省事。
2. Windows中, 就把snprintf和strncpy理解為類似的, 要用sizeof(str) - 1, 需要注意最后的’\0’, 當(dāng)然啦,你可以在每次用strncpy之前,利用memset將串清零, 這樣比較好。VC++6.0中的_snprintf(snprintf)并沒有按要求實(shí)現(xiàn), 暈。

總結(jié)

以上是生活随笔為你收集整理的各种输出函数的比较(printf/fprintf/sprintf/snprintf/vprintf/vfprintf/vsprintf/vsnprintf)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。