天天看點

c語言itoa函數頭檔案_全新版本printf函數你可能沒玩過

c語言itoa函數頭檔案_全新版本printf函數你可能沒玩過
c語言itoa函數頭檔案_全新版本printf函數你可能沒玩過
c語言itoa函數頭檔案_全新版本printf函數你可能沒玩過

C語言可變參數函數

C 語言允許定義參數數量可變的函數,這稱為可變參數函數。這種函數需要固定數量的強制參數,後面是數量可變的可選參數。這種函數必須至少有一個強制參數。可選參數的類型可以變化。可選參數的數量由強制參數的值決定,或由用來定義可選參數清單的特殊值決定。

C 語言中最常用的可變參數函數例子是 printf()和 scanf()。這兩個函數都有一個強制參數,即格式化字元串。格式化字元串中的轉換修飾符決定了可選參數的數量和類型。對于每一個強制參數來說,函數頭部都會顯示一個适當的參數,像普通函數聲明一樣。參數清單的格式是強制性參數在前,後面跟着一個逗号和省略号(...),這個省略号代表可選參數。

可變參數函數要擷取可選參數時,必須通過一個類型為 va_list 的對象,它包含了參數資訊。這種類型的對象也稱為參數指針(argument pointer),它包含了棧中至少一個參數的位置。可以使用這個參數指針從一個可選參數移動到下一個可選參數,由此,函數就可以擷取所有的可選參數。va_list 類型被定義在頭檔案 stdarg.h 中。

c語言itoa函數頭檔案_全新版本printf函數你可能沒玩過
c語言itoa函數頭檔案_全新版本printf函數你可能沒玩過
c語言itoa函數頭檔案_全新版本printf函數你可能沒玩過

如何實作

C語言可變參數通過三個宏(va_start、va_end、va_arg)和一個類型(va_list)實作的

  1. void va_start ( va_list ap, paramN );功能:初始化可變參數清單
  2. void va_end ( va_list ap );功能:關閉初始化清單(将 ap 置空)。
  3. type va_arg ( va_list ap, type );功能:傳回下一個參數的值。

好了,綜合上面3個宏和一個類型可以猜出如何實作C語言可變長參數函數:

va_start 擷取參數清單(的位址)存儲到 ap 中,va_arg 逐個擷取值,最後用 va_arg 将 ap 置空。

c語言itoa函數頭檔案_全新版本printf函數你可能沒玩過
c語言itoa函數頭檔案_全新版本printf函數你可能沒玩過
c語言itoa函數頭檔案_全新版本printf函數你可能沒玩過

小試牛刀

#include #include #define END -1int va_sum(int first_num, ...){    // (1) 定義參數清單    va_list ap;    // (2) 初始化參數清單    va_start(ap, first_num);    int result = first_num;    int temp = 0;    // 擷取參數值    while ((temp = va_arg(ap, int))!=END){        result += temp;    }    // 關閉參數清單    va_end(ap);    return result;}int main(){    printf("%d\n", va_sum(1, 2, 3, 4,END));    printf("%d\n", va_sum(1, 2, 3, 4, 5, END));    return 0;}           
c語言itoa函數頭檔案_全新版本printf函數你可能沒玩過
c語言itoa函數頭檔案_全新版本printf函數你可能沒玩過
c語言itoa函數頭檔案_全新版本printf函數你可能沒玩過

注意項

  1. 宏定義在 stdarg.h 中,是以使用時,不要忘了添加頭檔案。
  2. 設定一個參數結束标志(cplusplus 上說,va_arg 并不能确定哪個參數是最後一個參數)。
  3. 類型的比對
c語言itoa函數頭檔案_全新版本printf函數你可能沒玩過
c語言itoa函數頭檔案_全新版本printf函數你可能沒玩過
c語言itoa函數頭檔案_全新版本printf函數你可能沒玩過

漸入佳境

我們一起來偷看下“内褲”,發現标準庫中是這樣聲明printf函數的。

c語言itoa函數頭檔案_全新版本printf函數你可能沒玩過

最終你要學習就是這個:int printf(const char * format, ...);下面我們來寫一個簡單的可變參數的C 函數printf函數

#include 
#include 
#include 
#include 
int myvfprintf(FILE* stream, const char* format, va_list arglist){
int translating = 0;
int ret = 0; //記錄最終輸出的字元個數
const char* p = 0;
for (p = format; *p != '\0'; ++p)
    {
switch (*p)
        {
case '%':
if (!translating)
            {
                translating = 1; //translating置為1,代表後面的字元需要解析
            }
else
            {
if (fputc('%', stream) < 0)
return EOF;
                ++ret;
                translating = 0;
            }
break;
case 'd':
if (translating) //%d
            {
char buf[16];
                translating = 0;
                _itoa_s(va_arg(arglist, int), buf, 10);
if (fputs(buf, stream) < 0)
return EOF;
                ret += strlen(buf);
            }
else if (fputc('d', stream) < 0)
return EOF;
else
                ++ret;
break;
case 's':
if (translating)
            {
const char* str = va_arg(arglist, const char*);
                translating = 0;
if (fputs(str, stream) < 0)
return EOF;
                ret += strlen(str);
            }
else if (fputc('s', stream) < 0)
return EOF;
else
                ++ret;
break;
default:
if (translating)
                translating = 0;
if (fputc(*p, stream) < 0)
return EOF;
else
                ++ret;
break;

        }
    }
return ret;
}
int myprintf(const char* format, ...){
    va_list(arglist);
    va_start(arglist, format);
return myvfprintf(stdout, format, arglist);
}
int main(){
printf("%s\n", "ILoveyou");
    myprintf("%s\n", "ILoveyou");
return 0;
}                

運作測試結果:

c語言itoa函數頭檔案_全新版本printf函數你可能沒玩過
c語言itoa函數頭檔案_全新版本printf函數你可能沒玩過
c語言itoa函數頭檔案_全新版本printf函數你可能沒玩過
c語言itoa函數頭檔案_全新版本printf函數你可能沒玩過

結束語

文章都是手打原創,每天最淺顯的介紹C語言、C++,windows知識,喜歡我的文章就關注一波吧,每天帶你學習C/C++不同的知識,也可以看到最新更新和之前發表的文章哦。如果今天學到知識的,可以在留言區留言學到了哦,如果喜歡可以收藏,轉發,評論哦,這真的對我很重要!!

c語言itoa函數頭檔案_全新版本printf函數你可能沒玩過