_vsnprintf 用法
生活随笔
收集整理的這篇文章主要介紹了
_vsnprintf 用法
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
_vsnprintf,C語(yǔ)言庫(kù)函數(shù)之一,屬于可變參數(shù)。用于向字符串中打印數(shù)據(jù)、數(shù)據(jù)格式用戶自定義。
頭文件:
#include <stdarg.h>
函數(shù)聲明:
int _vsnprintf(char* str, size_t size, const char* format, va_list ap);
參數(shù)說(shuō)明:
char *str [out],把生成的格式化的字符串存放在這里.
size_t size [in], str可接受的最大字節(jié)數(shù),防止產(chǎn)生數(shù)組越界.
const char *format [in], 指定輸出格式的字符串,它決定了你需要提供的可變參數(shù)的類型、個(gè)數(shù)和順序。
va_list ap [in], va_list變量. va:variable-argument:可變參數(shù)
函數(shù)功能:將可變參數(shù)格式化輸出到一個(gè)字符數(shù)組。
用法類似于vsprintf,不過(guò)加了size的限制,防止了內(nèi)存溢出(size為str所指的存儲(chǔ)空間的大小)。
返回值:執(zhí)行成功,返回寫入到字符數(shù)組str中的字符個(gè)數(shù)(不包含終止符),最大不超過(guò)size;執(zhí)行失敗,返回負(fù)值,并置errno.[1]
備注:
linux環(huán)境下是:vsnprintf
VC6環(huán)境下是:_vsnprintf #include <stdio.h>
#include <stdarg.h>
int mon_log(char* format, ...)
{
char str_tmp[50];
int i=0;
va_list vArgList; //定義一個(gè)va_list型的變量,這個(gè)變量是指向參數(shù)的指針.
va_start (vArgList, format); //用va_start宏初始化變量,這個(gè)宏的第二個(gè)參數(shù)是第一個(gè)可變參數(shù)的前一個(gè)參 //數(shù),是一個(gè)固定的參數(shù).
i=_vsnprintf(str_tmp, 50, format, vArgList); //注意,不要漏掉前面的_
va_end(vArgList); //用va_end宏結(jié)束可變參數(shù)的獲取
return i; //返回參數(shù)的字符個(gè)數(shù)中間有逗號(hào)間隔
}
//調(diào)用上面的函數(shù)
void main(){int i=mon_log("%s,%d,%d,%d","asd",2,3,4);printf("%d\n",i);}
輸出 9。
asd,2,3,4
123456789 (共9個(gè)字符,間隔符逗號(hào)計(jì)算在內(nèi))
返回值用法:
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
char *make_message(const char *fmt, ...) {
/* 初始時(shí)假設(shè)我們只需要不超過(guò)100字節(jié)大小的空間 */
int n, size = 100;
char *p;
va_list ap;
if ( (p = (char *) malloc(size*sizeof(char))) == NULL)
return NULL;
while (1) {
/* 嘗試在申請(qǐng)的空間中進(jìn)行打印操作 */
va_start(ap, fmt);
n = vsnprintf (p, size, fmt, ap);
va_end(ap);
/* 如果vsnprintf調(diào)用成功,返回該字符串 */
if (n > -1 && n < size)
return p;
/* vsnprintf調(diào)用失敗(n<0),或者p的空間不足夠容納size大小的字符串(n>=size),嘗試申請(qǐng)更大的空間*/
size *= 2; /* 兩倍原來(lái)大小的空間 */
if ((p = (char *)realloc(p, size*sizeof(char))) == NULL)
return NULL;
}
}
int main() {
/* 調(diào)用上面的函數(shù) */
char* str = make_message("%d,%d,%d,%d",5,6,7,8);
printf("%s\n",str);
free(str);
/* 輸出5,6,7,8*/
return 0;
}
代碼在vc6.0下調(diào)試通過(guò)。 本文主要介紹va_start和va_end的使用及原理。在以前的一篇帖子Format MessageBox 詳解中曾使用到va_start和va_end這兩個(gè)宏,但對(duì)它們也只是泛泛的了解。介紹這兩個(gè)宏之前先看一下C中傳遞函數(shù)的參數(shù)時(shí)的用法和原理: 1.在C中,當(dāng)我們無(wú)法列出傳遞函數(shù)的所有實(shí)參的類型和數(shù)目時(shí),可以用省略號(hào)指定參數(shù)表void foo(...);
void foo(parm_list,...);
這種方式和我們以前認(rèn)識(shí)的不大一樣,但我們要記住這是C中一種傳參的形式,在后面我們就會(huì)用到它。2.函數(shù)參數(shù)的傳遞原理函數(shù)參數(shù)是以數(shù)據(jù)結(jié)構(gòu):棧的形式存取,從右至左入棧。首先是參數(shù)的內(nèi)存存放格式:參數(shù)存放在內(nèi)存的堆棧段中,在執(zhí)行函數(shù)的時(shí)候,從最后一個(gè)開始入棧。因此棧底高地址,棧頂?shù)偷刂?#xff0c;舉個(gè)例子如下:
void func(int x, float y, char z);那么,調(diào)用函數(shù)的時(shí)候,實(shí)參 char z 先進(jìn)棧,然后是 float y,最后是 int x,因此在內(nèi)存中變量的存放次序是 x->y->z,因此,從理論上說(shuō),我們只要探測(cè)到任意一個(gè)變量的地址,并且知道其他變量的類型,通過(guò)指針移位運(yùn)算,則總可以順藤摸瓜找到其他的輸入變量。下面是 <stdarg.h> 里面重要的幾個(gè)宏定義如下:
typedef char* va_list;
void va_start ( va_list ap, prev_param ); /* ANSI version */
type va_arg ( va_list ap, type );
void va_end ( va_list ap );
va_list 是一個(gè)字符指針,可以理解為指向當(dāng)前參數(shù)的一個(gè)指針,取參必須通過(guò)這個(gè)指針進(jìn)行。
<Step 1> 在調(diào)用參數(shù)表之前,定義一個(gè) va_list 類型的變量,(假設(shè)va_list 類型變量被定義為ap);
<Step 2> 然后應(yīng)該對(duì)ap 進(jìn)行初始化,讓它指向可變參數(shù)表里面的第一個(gè)參數(shù),這是通過(guò) va_start 來(lái)實(shí)現(xiàn)的,第一個(gè)參數(shù)是 ap 本身,第二個(gè)參數(shù)是在變參表前面緊挨著的一個(gè)變量,即“...”之前的那個(gè)參數(shù);
<Step 3> 然后是獲取參數(shù),調(diào)用va_arg,它的第一個(gè)參數(shù)是ap,第二個(gè)參數(shù)是要獲取的參數(shù)的指定類型,然后返回這個(gè)指定類型的值,并且把 ap 的位置指向變參表的下一個(gè)變量位置;
<Step 4> 獲取所有的參數(shù)之后,我們有必要將這個(gè) ap 指針關(guān)掉,以免發(fā)生危險(xiǎn),方法是調(diào)用 va_end,他是輸入的參數(shù) ap 置為 NULL,應(yīng)該養(yǎng)成獲取完參數(shù)表之后關(guān)閉指針的習(xí)慣。說(shuō)白了,就是讓我們的程序具有健壯性。通常va_start和va_end是成對(duì)出現(xiàn)。
例如 int max(int n, ...); 其函數(shù)內(nèi)部應(yīng)該如此實(shí)現(xiàn):
#include <iostream.h>
void fun(int a, ...)
{ int *temp = &a;temp++;for (int i = 0; i < a; ++i) { cout << *temp << endl; temp++; }
}
int main()
{ int a = 1; int b = 2; int c = 3; int d = 4; fun(4, a, b, c, d); system("pause"); return 0;
} Output::
1
2
3
43:獲取省略號(hào)指定的參數(shù)在函數(shù)體中聲明一個(gè)va_list,然后用va_start函數(shù)來(lái)獲取參數(shù)列表中的參數(shù),使用完畢后調(diào)用va_end()結(jié)束。像這段代碼:
void TestFun(char* pszDest, int DestLen, const char* pszFormat, ...)
{
va_list args;
va_start(args, pszFormat); //一定要“...”之前的那個(gè)參數(shù)
_vsnprintf(pszDest, DestLen, pszFormat, args);
va_end(args);
}4.演示如何使用參數(shù)個(gè)數(shù)可變的函數(shù),采用ANSI標(biāo)準(zhǔn)形式
#include 〈stdio.h〉
#include 〈string.h〉
#include 〈stdarg.h〉 /*函數(shù)原型聲明,至少需要一個(gè)確定的參數(shù),注意括號(hào)內(nèi)的省略號(hào)*/
int demo( char, ... );
void main( void )
{ demo("DEMO", "This", "is", "a", "demo!", "");
} /*ANSI標(biāo)準(zhǔn)形式的聲明方式,括號(hào)內(nèi)的省略號(hào)表示可選參數(shù)*/
int demo( char msg, ... )
{ /*定義保存函數(shù)參數(shù)的結(jié)構(gòu)*/va_list argp; int argno = 0; char para; /*argp指向傳入的第一個(gè)可選參數(shù),msg是最后一個(gè)確定的參數(shù)*/ va_start( argp, msg ); while (1) { para = va_arg( argp, char); if ( strcmp( para, "") == 0 ) break; printf("Parameter #%d is: %s\n", argno, para); argno++;
}
va_end( argp );
/*將argp置為NULL*/
return 0;
}以上是對(duì)va_start和va_end的介紹。最后,希望轉(zhuǎn)載的朋友能夠尊重作者的勞動(dòng)成果,加上轉(zhuǎn)載地址:http://www.cnblogs.com/hanyonglu/archive/2011/05/07/2039916.html 謝謝。
完畢。^_^
?
總結(jié)
以上是生活随笔為你收集整理的_vsnprintf 用法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: SQL Server 为什么事务日志自动
- 下一篇: js setTimeout()的使用