可變引數列表原始碼的剖析

2021-08-19 01:41:39 字數 1785 閱讀 1461

在某些情況下我們希望函式引數的個數可以根據實際需要來確定,所以c語言中就提供了一種長度不確定的引數,形如:「…」,通過將函式實現為可變引數的形式,可以使得函式可以接受1個以上的任意多個引數。

典型的例子有printf()、scanf()函式等,下面就用printf函式的原型為例分析:

int printf( const char *format [, argument]... );
如上,除了引數format固定以外,其他引數的型別和個數是不確定的。在實際呼叫的時候有如下型別:

printf("%d",num);

printf("%s",num);

printf("%c",num);

...

在標準c語言中定義了乙個標頭檔案,專門用來對付可變引數列表,其中,包含了乙個va_list的typedef宣告和一組巨集定義va_start、va_arg、va_end,如下所示:

va_list arg;

va_start(arg, n);

va_arg(arg, (資料型別) );

va_end(arg);

va_list:宣告乙個va_list型別的變數arg,它可以訪問引數列表的未確定部分。

這個變數是呼叫va_start來初始化的。它的第乙個引數是va_list的變數名,第2個引數是省略號前最後乙個有名字的引數。初始化過程把arg變數設定為指向可變引數部分的第乙個引數。

va_arg:這個巨集和接受兩個引數,va_list變數和引數列表中下乙個引數的型別。在這個例子中所有的可變引數都是整型。va_arg返回這個引數的值,並使用va_arg指向下乙個可變引數。

va_end:訪問完畢最後乙個可變引數,通過va_end(ap)讓ap不再指向堆疊。

例:自定義的列印函式

int my_printf(char *str, ...)

; va_start(arg, str);

while (*str != '\0')

break;

case

'c':

putchar(va_arg(arg, int));

break;

case

'd':

int d = va_arg(arg, int);

_itoa(d, buf, 10);

for (str_tmp = buf; *str_tmp; str_tmp++)

break;

case

'\n':

puts(" ");

break;

default:

;break;

}str++;

}va_end(arg);

return0;}

int main()

由於將va_start、va_arg、va_end定義成了巨集,可變引數的型別和個數在該函式中完全由程式**控制,並不能智慧型地進行識別,所以導致編譯器對可變引數的函式原型檢查不夠嚴格,難於查錯,不利於寫出高質量的**。

——《編寫高質量**》

雖然引數可變為程式設計師帶來了很多便利,但也有一些不可避免的缺陷。比如:

1.缺乏型別檢查,型別安全性不能保證。

2.因為禁用了語言型別檢查功能,所以在呼叫時必須通過其他方式告訴函式所傳遞引數的型別。

3.不支援自定義資料型別。

以上,因為編譯器對可變引數函式的原型檢查不夠嚴格,所以容易引起問題,難於查錯,不利於寫出高質量的**。所以應當盡量避免使用c語言方式的可變引數設計。

可變引數列表原始碼剖析

c語言中的可變引數列表,顧名思義,在c語言中有一些特殊的函式,它們的引數不是固定的,可以是多種型別的任意多個引數。比如最常用的printf函式和scanf函式,通過使用可變引數列表,使函式可以接收 1個的多種型別的引數。用printf函式的原型來舉例子 int printf const char f...

可變引數列表原始碼的剖析

c語言中的可變引數 1 c語言中的可變引數列表 c語言中有時候會遇到一些引數個數是可變的函式,像scanf,printf等,這些函式內部的引數列表都是可變的。通過將函式實現為可變引數的形式,使得函式可以接受1個以上的任意多個引數。不固定 如函式原型 scanf const char format,解...

可變引數列表原始碼的剖析

首先看看main函式的引數 首先我們得知道main函式是有引數的,那麼我們就來看看main函式的原型 int main int argc,int argv,char envp program statements 那麼我們看到這裡有三個引數 第乙個引數 argc是個整形引數,表示命令行引數的個數 含...