Quake源碼的一個參數引用技巧

王朝other·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

曾經在Quake源碼里看到下面一段代碼:

int VM_Call( vm_t *vm, int instruction, ... ) {

va_list argptr;

int arg0;

int arg1;

int arg2;

int arg3;

int arg4;

int arg5;

int arg6;

if( !vm ) {

Com_Error( ERR_FATAL, "VM_Call with NULL vm" );

}

//Com_Printf( "VM_Call( %i )\n", instruction );

va_start( argptr, instruction );

arg0 = va_arg( argptr, int );

arg1 = va_arg( argptr, int );

arg2 = va_arg( argptr, int );

arg3 = va_arg( argptr, int );

arg4 = va_arg( argptr, int );

arg5 = va_arg( argptr, int );

arg6 = va_arg( argptr, int );

va_end( argptr );

return vm->vmMain( instruction, arg0, arg1, arg2, arg3, arg4, arg5, arg6 );

}

引起我興趣的是VM_Call( vm_t *vm, int instruction, ... ) 中參數聲明的部分."..."這個關鍵字我是從來沒有看見過,覺得很是新奇.它的作用感覺是要騙過編譯器,使它不對vm_t *vm, int instruction以後所傳入的參數類型和個數進行檢查.換句話說就是不論函數調用者有多少參數,都可以一次性地壓入堆棧中.那麼函數本身如何去利用堆棧中的參數呢?我們還是先去看看下面系統定義的宏:

typedef char * va_list;

#ifdef _M_IX86

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

#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )

#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )

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

#elif defined(_M_MRX000)

/* Use these types and definitions if generating code for MIPS */

#define va_start(ap,v) ap = (va_list)&v + sizeof(v)

#define va_end(list)

#define va_arg(list, mode) ((mode *)(list = (char *) ((((int)list + (__builtin_alignof(mode)<=4?3:7)) & (__builtin_alignof(mode)<=4?-4:-8))+sizeof(mode))))[-1]

/* +++++++++++++++++++++++++++++++++++++++++++

Because of parameter passing conventions in C:

use mode=int for char, and short types

use mode=double for float types

use a pointer for array types

+++++++++++++++++++++++++++++++++++++++++++ */

#elif defined(_M_ALPHA)

我們知道函數內部使用的變量都是在堆棧中開闢空間,而且堆棧的生長方向是從高地址向低地址生長.如果跳過函數定義的第一個變量,我們就來到了存放參數的棧頂,也就是#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )

這個宏的涵義.#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )則是把參數逐個的從堆棧中取出,但並不是出棧,這裡要注意.

可是為甚麼要採用這種看起來比較彆扭的方式來傳遞參數呢?主要原因是讓代碼能夠在多個編譯器上編譯,並且保證執行效果一樣.每種編譯器所定義的原始數據類型的字节長度也許是不同的.

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
 
© 2005- 王朝網路 版權所有 導航