RTSP協議的一些分析(二)——printf類似函數、sscanf以及log保存到內存中(printf輸入重定位)
1、printf函數
#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);
#include <stdio.h>
#include <string.h>
//data and place them in the string named buffer.
// 程序使用sprintf 將各種數據格式化後置於字符數組buffer中
#include <stdio.h>
int main( void )
{
char buffer[200], s[] = "computer", c = 'l';
int i = 35, j;
float fp = 1.7320534f;
// 格式化並打印各種數據到buffer
j = sprintf( buffer," String: %s\n", s ); // C4996
j += sprintf( buffer + j, " Character: %c\n", c ); // C4996
j += sprintf( buffer + j, " Integer: %d\n", i ); // C4996
j += sprintf( buffer + j, " Real: %f\n", fp );// C4996
printf( "Output:\n%s\ncharacter count = %d\n", buffer, j );
return 0;
}
2、printf重定位
#include <stdio.h>
#include <stdarg.h>
int myPrintf(const char *fmt,...)
{
int i;
char str_tmp[100];
va_list args;
/* void va_start(va_list ap, last) */
va_start(args,fmt);
/*
* 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);
*/
i=vsnprintf(str_tmp,100,fmt,args);
/* void va_end(va_list ap) */
va_end(args);
/* 可以打印,或者保存到緩衝區中 */
printf("i = %d, %s",i,str_tmp);
}
int main(int argc,char **agrv)
{
int i = 5,j = 6;
char *str = "123456";
myPrintf("[yangguoyu]: i = %d,j= %d,str = %s\n",i,j,str);
return 0;
}
1)va_list:一個字符指針,可以理解爲指向當前參數的一個指針,取參必須通過這個指針進行。
2)va_start:對ap進行初始化,讓ap指向可變參數表裏面的第一個參數。第一個參數是 ap 本身,第二個參數是在變參表前面緊挨着的一個變量,即“...”之前的那個參數;
3)va_arg: 獲取參數。它的第一個參數是ap,第二個參數是要獲取的參數的指定類型。按照指定類型獲取當前參數,返回這個指定類型的值,然後把 ap 的位置指向變參表中下一個變量的位置;
4)va_end:釋放指針,將輸入的參數 ap 置爲 NULL。通常va_start和va_end是成對出現。
int vsnprintf (char * s, size_t n, const char * format, va_list arg )
描述:
將格式化數據從可變參數列表寫入大小緩衝區,如果在printf上使用格式,則使用相同的文本組成字符串,但使用由arg標識的變量參數列表中的元素而不是附加的函數參數,並將結果內容作爲C字符串存儲在s指向的緩衝區中 (以n爲最大緩衝區容量來填充)。如果結果字符串的長度超過了n-1個字符,則剩餘的字符將被丟棄並且不被存儲,而是被計算爲函數返回的值。在內部,函數從arg標識的列表中檢索參數,就好像va_arg被使用了一樣,因此arg的狀態很可能被調用所改變。在任何情況下,arg都應該在調用之前的某個時刻由va_start初始化,並且在調用之後的某個時刻,預計會由va_end釋放。
參數:
s:指向存儲結果C字符串的緩衝區的指針。緩衝區應至少有n個字符的大小。
n:在緩衝區中使用的最大字節數。生成的字符串的長度至多爲n-1,爲額外的終止空字符留下空間。size_t是一個無符號整數類型。
format:包含格式字符串的C字符串,其格式字符串與printf中的格式相同。
arg:標識使用va_start初始化的變量參數列表的值。va_list是在<cstdarg>中定義的特殊類型。
返回值:
如果n足夠大,則會寫入的字符數,不包括終止空字符。
如果發生編碼錯誤,則返回負數。
注意,只有當這個返回值是非負值且小於n時,字符串才被完全寫入。
3. sscanf
int sscanf(const char *str, const char *format, ...);
作用: 從一個字符串中讀進與指定格式相符的數據.
參數:buffer 存儲的數據
format 格式控制字符串
返回值:成功則返回參數數目,失敗則返回0,錯誤原因存於errno中。
說明:
sscanf與scanf類似,都是用於輸入的,只是後者以鍵盤(stdin)爲輸入源,前者以固定字符串爲輸入源。
第一個參數可以是一個或多個 {%[*] [width] [{h | l | I64 | L}]type | ' ' | '\t' | '\n' | 非%符號}
注:
1、 * 亦可用於格式中, (即 %*d 和 %*s) 加了星號 (*) 表示跳過此數據不讀入. (也就是不把此數據讀入參數中)
2、{a|b|c}表示a,b,c中選一,[d],表示可以有d也可以沒有d。
3、width表示讀取寬度。
4、{h | l | I64 | L}:參數的size,通常h表示單字節size,I表示2字節 size,L表示4字節size(double例外),l64表示8字節size。
5、type :這就很多了,就是%s,%d之類。
6、特別的:%*[width] [{h | l | I64 | L}]type 表示滿足該條件的被過濾掉,不會向目標參數中寫入值
失敗返回0 ,否則返回格式化的參數個數
支持集合操作:
%[a-z] 表示匹配a到z中任意字符,貪婪性(儘可能多的匹配)
%[aB'] 匹配a、B、'中一員,貪婪性
%[^a] 匹配非a的任意字符,並且停止讀入,貪婪性 。
#include <stdio.h>
#include <string.h>
int main(int argc,char **argv[])
{
char buf[512];
/* 1.常用用法 */
sscanf("123456 ","%s",buf);/*此處buf是數組名,它的意思是將123456以%s的形式存入buf中!*/
printf("1,-%s-\n",buf);
/* 2.取指定長度的字符串。如在下例中,取最大長度爲4字節的字符串。*/
sscanf("123456 ", "%4s", buf);
printf("2,-%s-\n",buf);
/* 3. 取到指定字符爲止的字符串。如在下例中,取遇到空格爲止字符串。 */
sscanf("123456 abcdedf", "%[^ ]", buf);
printf("3,-%s-\n",buf);
/* 4. 取僅包含指定字符集的字符串。如在下例中,取僅包含1到9和小寫字母的字符串。 */
sscanf("123456abcdedfBCDEF", "%[1-9a-z]", buf);
printf("4,-%s-\n",buf);
/* 5. 取到指定字符集爲止的字符串。如在下例中,取遇到大寫字母爲止的字符串*/
sscanf("123456abcdedfBCDEF","%[^A-Z]", buf);
printf("5,-%s-\n",buf);
/* 6. 給定一個字符串iios/12DDWDFF@122,獲取/和 @ 之間的字符串,先將 "iios/"過濾掉,再將非'@'的一串內容送到buf中 */
sscanf("iios/12DDWDFF@122", "%*[^/]/%[^@]", buf);
printf("6,-%s-\n",buf);
/* 7. 給定一個字符串"hello, world",僅保留world。(注意:","之後有一空格,%s遇空格停止,加*則是忽略第一個讀到的字符串) */
sscanf("hello, world", "%*s%s", buf);
printf("7,-%s-\n",buf);
return 0;
}
運行結果:
1,-123456-
2,-1234-
3,-123456-
4,-123456abcdedf-
5,-123456abcdedf-
6,-12DDWDFF-
7,-world-