在寫程式的時候用到了可變引數,但是在除錯程式的時候發現,當可變引數為float型別的時候竟然是出了莫名其妙的一些錯誤,搞得一頭霧水一臉懵逼,上網查查去,看到了這樣的帖子:
2015-09-14 0 comments 197 views 0 times
今天嘗試著使用va_arg
來寫乙個my_printf()
函式,目的就是做到像printf()
那樣可以格式化輸出。
首先,想到的就是通過可變長引數來傳遞引數。之所以這樣做是因為我們不能確定每次呼叫my_printf()
的時候,會使用幾個實參。
stdarg.h
就是這個可變長引數的標頭檔案,裡面定義了以下幾個函式:
va_start() //使va_list指向起始的引數
va_list() //用來儲存巨集va_arg與巨集va_end所需資訊
va_arg() //檢索引數
va_end() //釋放va_list
va_copy() //拷貝va_list的內容
大致就是這樣。
我們在定義函式的時候,就可以這樣定義:
void fun(int i,...);
這裡的三個點…就是代表著可變長引數。
然後,我們可以在這個函式內這樣獲得引數:
void fun(int i,...)
從上面的示範可以知道,函式定義的時候,可變長引數(…)不能放在形參的第乙個。必須有乙個引數來使得va_start()
來定位可變長引數(…)的位置。型別基本隨意。
然後,用va_list()
來建立引數列表。並且用va_start()
來初始化列表為傳入的可變長引數。
然後,通過用va_arg()
函式來依次讀取引數列表中的引數。這裡va_arg(ap,type)
中,ap
指引數列表,type
指轉換型別。
注意!注意!注意!
type
絕對不能為以下型別:
——char、signed char、unsigned char
——short、unsigned short
——signed short、short int、signed short int、unsigned short int
——float
乙個float
坑了我半個小時!血的教訓啊!
最後,不要忘記用va_end()
來釋放引數列表。
在除錯這個引數列表的時候,可能在一行報錯,但是其實真正的錯誤在於上一次va_arg()
讀取引數的時候。
比如:
va_arg(var_arg,float);
從前面的警告可以看出,這裡使用了float
的型別轉換,是不允許的。但是,那時候我沒發現這個問題。而這個float
導致讀取引數出錯。然而,編譯器真正報錯的地方不在此處,而是在下乙個型別為(char *)
引數讀取使用的時候。害得我找了好久關於指標位址的問題,結果最後發現是前乙個float
引數的讀取錯誤導致之後的(char *)
引數的錯誤讀取,最後導致了bug的出現。
所以,對於可變長引數的使用要非常小心,要考慮更加周全一點點,才能減少bug的出現。
可變引數及可變引數巨集的使用
我們在c語言程式設計中會遇到一些引數個數可變的函式,例如printf 這個函式,這裡將介紹可變函式的寫法以及原理.一般在除錯列印debug 資訊的時候,需要可變引數的巨集.從c99開始可以使編譯器標準支援可變引數巨集 variadic macros 另外gcc 也支援可變引數巨集,但是兩種在細節上可...
C語言的變長引數 va arg
void va fun int i,這個函式用來格式化帶引數的字串 int vspf char fmt,extern inline attribute always inline int f3 int y,inttest void extern int open real const char in...
LINUX 可變引數的使用
1 首先在函式裡定義乙個va list型的變數,這裡是arg ptr,這個變數是指向引數的指標.2 然後用va start巨集初始化變數arg ptr,這個巨集的第二個引數是第乙個可變引數的前乙個參 數,是乙個固定的引數.3 然後用va arg返回可變的引數,並賦值給整數j.va arg的第二個引數...