可變引數及對齊

2021-08-31 04:32:52 字數 2181 閱讀 9064

轉貼部分:

va_list arg_ptr:定義乙個指向個數可變的引數列表指標;

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)。

va_arg(arg_ptr, type):返回引數列表中指標arg_ptr所指的引數,返回型別為type,並使指標arg_ptr指向引數列表中下乙個引數。

va_copy(dest, src):dest,src的型別都是va_list,va_copy()用於複製引數列表指標,將dest初始化為src。

va_end(arg_ptr):清空引數列表,並置引數指標arg_ptr無效。說明:指標arg_ptr被置無效後,可以通過呼叫 va_start()、va_copy()恢復arg_ptr。每次呼叫va_start() / va_copy()後,必須得有相應的va_end()與之匹配。引數指標可以在引數列表中隨意地來回移動,但必須在va_start() … va_end()之內。

◎用法:

func( type para1, type para2, type para3, ... )

◎研究:

typedef char * va_list;

#define va_start _crt_va_start

#define va_arg _crt_va_arg

#define va_end _crt_va_end

#define _crt_va_start(ap,v) ( ap = (va_list)_addressof(v) + _intsizeof(v) )

#define _crt_va_arg(ap,t) ( *(t *)((ap += _intsizeof(t)) - _intsizeof(t)) )    加了又減很神奇啊!果然高手就是不一樣!

#define _crt_va_end(ap) ( ap = (va_list)0 )

va_list argptr;

c語言的函式是從右向左壓入堆疊的,呼叫va_start後,

按定義的巨集運算,_addressof得到v所在的位址,然後這個

位址加上v的大小,則使ap指向第乙個可變引數如圖:

棧底 高位址

| .......

| 函式返回位址

| .......

| 函式最後乙個引數

| ....

| 函式第乙個可變引數 <--va_start後ap指向

| 函式最後乙個固定引數

| 函式第乙個固定引數

棧頂 低位址

然後,用va_arg()取得型別t的可變引數值, 先是讓ap指向下乙個引數:

ap += _intsizeof(t),然後在減去_intsizeof(t),使得表示式結果為

ap之前的值,即當前需要得到的引數的位址,強制轉換成指向此引數的

型別的指標,然後用*取值

最後,用va_end(ap),給ap初始化,保持健壯性。

注意部分:

1. 函式在傳遞引數是從右到左入棧

2. char型別引數雖然佔乙個位元組但是在作為引數時是按照對齊來的,下乙個引數與他差4個位元組

void foo(char a, char b, int c , int d)

printf("a: %p\n", &a);

printf("b: %p\n", &b);

printf("c: %p\n", &c);

printf("d: %p\n", &d);

呼叫結果:

a: 0xbfafb98c

b: 0xbfafb988

c: 0xbfafb9a8

d: 0xbfafb9ac

從結果看也不符合這個規律,不清楚怎麼回事,以後再說。

3. 編譯器有記憶體對其功能。也就是在人為的基礎上再進一步對齊

struct aa;

struct bb;

此時sizeof(a)= 12

而sizeof(b) = 16

可見良好的程式設計還是比較重要的。

可變引數及可變引數巨集的使用

我們在c語言程式設計中會遇到一些引數個數可變的函式,例如printf 這個函式,這裡將介紹可變函式的寫法以及原理.一般在除錯列印debug 資訊的時候,需要可變引數的巨集.從c99開始可以使編譯器標準支援可變引數巨集 variadic macros 另外gcc 也支援可變引數巨集,但是兩種在細節上可...

可變引數列印 解析可變引數

1.的一般用法 define str s s define cons a,b int a e b int main 2.接受,列印可變引數 參考 glibc庫的bebug函式 define printf fmt,args.printf fmt,args 使用方法 define pr debug fm...

main函式引數及可變引數列表

c語言中main函式是程式的入口函式,一般在使用main函式的時候都是不帶引數的,那麼main函式帶上引數又如何呢?main函式形式 int main int argc,char argv,char envp 可知main函式有三個引數 1,argc 記錄命令列引數的個數 包含第乙個引數 可執行檔名...