函式不定引數個數的實現
1. C語言函式的呼叫方式 _cdecl 呼叫
_cdecl 是C Declaration的縮寫(declaration,宣告),表示C語言預設的函式呼叫方法:所有引數從右到左依次入棧,這些引數由呼叫者清除,稱為手動清棧所以在函式呼叫棧中, 越右邊的引數在棧的越低端,既記憶體地址越大。
2.實現
函式如何實現不定引數:由於在C語言中沒有函式過載,解決不定數目函式引數問題變得比較麻煩,即使採用C++,如果引數個數不能確定,也很難採用函式過載。對這種情況,提出了指標引數來解決問題。
(1)va_list
定義了一個指標arg_ptr, 用於指示可選的引數.
(2)va_start(arg_ptr, argN)
使引數列表指標arg_ptr指向函式引數列表中的第一個可選引數,argN是位於第一個可選引數之前的固定引數,
或者說最後一個固定引數.如有一va 函式的宣告是void va_test(char a, char b, char c, ...), 則它的固定引數依次是a,b,c, 最後一個固定引數argN為c, 因此就是va_start (arg_ptr, c).
(3)va_arg(arg_ptr, type)
返回引數列表中指標arg_ptr所指的引數, 返回型別為type. 並使指標arg_ptr指向引數列表中下一個引數.返回的是可選引數, 不包括固定引數.
(4)va_end(arg_ptr)
清空引數列表, 並置引數指標arg_ptr無效.
(注:va在這裡是variable-argument(可變引數)的意思. 這些巨集定義在stdarg.h中,所以用到可變引數的程式應該包含這個標頭檔案)
過程:
呼叫va_start()後parg將指向第一個不固定的引數,在這個函式中也就是v2後面的引數。
接著呼叫va_parg():va_parg同樣接受兩個引數第一個引數是經過va_start()處理過後的parg指標。
第二個引數是期望不固定引數的型別,編譯器無法確定可變引數的型別,但是必須這麼做。
va_parg返回parg當前指向的那個可變的引數。並且每次呼叫都會更新這個指標,使得parg向下個引數移動;
最後呼叫va_end():va_end接受一個引數,parg,他會將parg重置為NULL;沒用呼叫va_end函式將無法執行。
3.舉例
(1)固定引數個數(2個)
#include <stdio.h> #include <stdlib.h> #include <stdarg.h> int print(const char *format, ...) { va_list args; const char *args1; va_start(args, format); args1 = va_arg(args,const char *); va_end(args); printf("format=%s args1=%s", format, args1); } int main() { print("11111", "22222"); }
執行結果:
format=11111 args1=22222
(2)多個引數(採用迴圈)
double average(double v1, double v2, ...){ va_list parg; //將parg指向第一個不固定的引數 va_start(parg, v2); double sum = 0.0; sum = v1 + v2; double value; int count = 2; //va_arg判斷下一個不固定引數型別是否為double while((value = va_arg(parg, double)) != 0.0){ sum += value; ++count; } va_end(parg); return sum/count; }
4.注意
va_arg(ap,type)中的type絕對不能為以下型別:
——char、signed char、unsigned char
——short、unsigned short
——signed short、short int、signed short int、unsigned short int
——float
參考:
https://www.cnblogs.com/linhaostudy/p/6695422.html
https://blog.csdn.net/wabil/article/details/72800624?utm_source=blogxgwz0
https://blog.csdn.net/bristar_zon/article/details/48465021
https://blog.csdn.net/qq_25367755/article/details/50946574