基於C中變參的認識

2021-06-14 00:51:12 字數 2091 閱讀 9821

今天在工作之餘,突然有個朋友說到由於工作需要,需要用到c的變參。這個呢,以前大學裡面研究過,實習的時候也用到過,但是沒有怎麼深入,這次我決定深入的去了解一下c的變參是怎麼實現的。

首先看了printf的源**。下面將以printf為例子來說明。畢竟我們最先接觸的函式裡面就有這個函式。

先貼實現**,看了再說。(這裡我只解析 幾種變數,其他的解析是一樣的。)

#define  my_insizeof(n) ((sizeof(n) + sizeof(int) - 1)& ~(sizeof(int) - 1))

#define  my_va_list char *

#define  my_va_start(v, va) v = (my_va_list)&va + my_insizeof(va);

#define  my_va_end(v) v = 0

#define  my_va_arg(v, vsize) *(vsize *)((v += my_insizeof(vsize)) - my_insizeof(vsize))

void my_printf(char *format, ...)

else if(*(format + 1) == 's')

else if(*(format + 1) == 'd')

else if(*(format + 1) == 'f')

else

format++;

}else putc(*format, stdout);

format++;

}my_va_end(list);

}都知道函式呼叫的時候,引數傳遞的方式主要有2種,一種是通過將引數壓入堆疊的形式,一種是通過放入暫存器,但最常用的還是將引數壓入堆疊。而基於_stdcall呼叫,引數壓棧方式是從右到坐的方式。即各個引數的位址是緊挨著的,通過位址的操作可以訪問到下乙個引數的位址。上面是通過操作指標來實現訪問引數,後面還有一種通過彙編來實現引數解析

由於不同的引數型別,所佔的記憶體空間大小不一樣,那麼也就造成了在訪問記憶體時應該向後移幾位的問題,而且由於系統為了訪問快速,做引數做了位元組對齊,這裡的my_insizeof即是根據引數的大小做記憶體對齊,不然可能訪問的位址並不是真正的引數的位址,或許錯位了。

my_va_list 此巨集主要是用於操作記憶體單元,我們都知道,每乙個位元組為8位,而剛好每乙個char也是8位,那麼這裡也就是為了讓在訪問對應記憶體時能一位元組一位元組的訪問。

my_va_arg這個巨集很簡單,由於我們在函式開始執行時,list已經指向了函式的第二個引數。這個巨集的大致意思就是,將引數強制轉換為我們需要的型別,並將list指向下乙個引數的位址(可以理解為彙編中的esp)。

上面的是通過c的方式實現,看起來有點難懂,特別是巨集,下面以彙編的形式來解析引數,很好明白。(先看下面的彙編,再去看上面的c**方式,將會簡單多了)(這裡以輸出乙個字元為例,輸出其他引數是一樣,只是我們在讀出記憶體中的值的同時,根據我們需要的引數解析即可)

void my_printf2(char *format, ...)

putc(dst, stdout);

}else

++format;

}++format;}}

大部分**和上面的都差不多,而且這個**看著就少多了。上面彙編有注釋,這裡也就不多解釋了,我感覺用彙編來寫,**又簡潔又易懂。簡單多了。

上面還有值得注意的便是第一種方法在解析float型的時候,不能寫float型,因為系統在傳引數的時候,直接傳的double型,即我們要按照double型來解析,不然就解析的資料不對了,這裡我就不貼圖了,如果想自己證明的話,很簡單,直接看記憶體的值即可。還有,在傳遞浮點數的時候,如果是直接寫的引數的話,必須強制轉為為float或者double才能正確輸出,例如;printf("%f",123),那麼這樣列印出來的值其實是不對的,原因就是當你直接寫123的時候,系統並不知道你想以float的形式儲存,那麼系統將會自動以整形的形式儲存在記憶體中,但是我們在解析的時候,確是以浮點數的形式去解析,那麼將導致解析的值不對。所以在這種情況下,要麼我們可以定義乙個浮點數的變數,並在傳參的時候傳遞這個變數過去,要麼就是強制轉換,即

printf(「%s」,(float)123),這種的話,輸出結果是正確的。

浮點數的儲存方式並不像整形那樣,網上的介紹很多,不懂的可以去看看,如果以後有機會,我會將其記錄下來。

C語言變參使用

c語言中有很多變參的使用,例如printf 的原型是int printf const char fmt,那麼c語言是如何解析和處理這些變參的呢?下面進行簡單的總結 c語言中定義了下面的一些巨集,專門用來處理變參 va start va list ap,char fmt va arg va list ...

C語言(變參函式)

c語言雖然沒有c 的函式過載特性,但也可以實現變參,但要保證第乙個引數資訊的完整性。拓展 定義變參函式時,第乙個引數一般是字串,攜帶後續變參的型別和數量資訊,變參使用三點來表示,如 void sumup const char info,再使用va list va start va arg 和va e...

C語言變參,記錄

由於在 c語言中沒有函式過載 解決不定數目函式引數問題變得比較麻煩 即使採用 c 如果引數個數不能確定 也很難採用函式過載 對這種情況 有些人採用指標引數來解決問題.uhmm 用到的變參地方 用的原因 1,sql 語言必須用常量2,sql語言格式不相同,引數個數不相同使用a dyw mysql nu...