C處理不定參數(va_start)

在#include<stdarg.h>頭裏包含了四個宏函數

#define _INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1) )指針

#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) ) //第一個可選參數地址htm

#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) //下一個參數地址進程

#define va_end(ap) ( ap = (va_list)0 )get

函數實現的原理:test

首先:進程中的堆棧地址是從高到底分配的,那麼執行一個函數的過程:原理

先把參數地址入棧,接着是函數返回值地址入棧,接着入棧函數的執行代碼。這個過程當中地址不斷遞減(一些黑客就在這個過程當中加入本身的代碼執行)遍歷

最後一個參數地址  (最高地址)總結

倒數第二個參數地址 (次之)黑客

。。

第一個參數  (參數列表最低地址)

函數返回值

函數執行代碼

例子:

void arg_test(int i, ...)

{

int j=0;

va_list arg_ptr;

va_start(arg_ptr, i);

printf("&i = %p\n", &i);//打印參數i在堆棧中的地址

printf("arg_ptr = %p\n", arg_ptr);//打印va_start以後arg_ptr地址

/*這時arg_ptr應該比參數i的地址高sizeof(int)個字節,即指向下一個參數的地址*/

j=*((int *)arg_ptr);

printf("%d %d\n", i, j);

j=va_arg(arg_ptr, int);

printf("arg_ptr = %p\n", arg_ptr);//打印va_arg後arg_ptr的地址

/*這時arg_ptr應該比參數i的地址高sizeof(int)個字節,即指向下一個參數的地址,若是已是最後一個參數,arg_ptr會爲NULL*/

va_end(arg_ptr);

printf("%d %d\n", i, j);

}

總結:

int int_size = _INTSIZEOF(int);獲得int類型所佔字節數

va_start(arg_ptr, i); 獲得第一個可變參數地址

根據定義(va_list)&v獲得起始參數的地址, 再加上_INTSIZEOF(v) ,就是其實參數下一個參數的地址,即第一個可變參數地址.

j=va_arg(arg_ptr, int); 獲得第一個可變參數的值,而且arg_ptr指針上移一個_INTSIZEOF(int),即指向下一個可變參數的地址.

va_end(arg_ptr);置空arg_ptr,即arg_ptr=(void *)0;

總結:讀取可變參數的過程其實就是在堆棧中,使用指針,遍歷堆棧段中的參數列表,從低地址到高地址一個一個地把參數內容讀出來的過程.

相關文章
相關標籤/搜索