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

原创 2004年09月29日 14:33:00

       曾經在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)) )則是把參數逐個的從堆棧中取出,但並不是出棧,這裡要注意.
        可是為甚麼要採用這種看起來比較彆扭的方式來傳遞參數呢?主要原因是讓代碼能夠在多個編譯器上編譯,並且保證執行效果一樣.每種編譯器所定義的原始數據類型的字节長度也許是不同的.

mooc data structure 韩永楷 HW1.2(homework)

这道题主要就是第一周的课程的内容的训练,训练的是对归并排序(margesort)的运用; 题目: 题目内容: 在一個N個數字的序列S裡,當S[i] > S[j] 且 i Hint : 利用歸併...
  • nefu2015214119
  • nefu2015214119
  • 2016年02月25日 14:46
  • 620

C#中水晶报表实现动态传递参数的简单方法

在winform中用到水晶报表时,该水晶报表的数据源是一存储过程的结果集,那么可以动态的实现在程序中动态传递参数到存储过程中,从而可以轻松的产生相应的报表,但是报表的格式必须先设置好,动态传递参数的代...
  • fhb19870610
  • fhb19870610
  • 2009年08月13日 13:38
  • 1341

addEventListener的第三個參數

alimama_pid="mm_10096109_566393_892186"; alimama_titlecolor="0000FF"; alima...
  • xfu0311wxj
  • xfu0311wxj
  • 2008年03月20日 16:43
  • 334

Quake源代碼分析(草稿).3

消息處理:       我把Quake的消息分為兩類,一種是常用輸入設備產生的消息,譬如KeyBoard,Mouse,JoyStick等.       另一種就是網絡或本地傳輸數據包時引發的消息.  ...
  • amdk_7
  • amdk_7
  • 2006年05月18日 14:25
  • 862

SQl trigger 有两个表,其中一个表的数据变化,同时要影响到另一个表

問題1: 如果我的MS SQL 2005資料庫裡面有兩個Table 分別是A (裡面有兩個欄位 分別是name,tel)與B   (裡面有兩個欄位 分別是name,tel)接著我想要用Trigger ...
  • fengluoyan
  • fengluoyan
  • 2013年03月15日 18:44
  • 539

Oracle Procedure 数组参数的应用

因工作需要,数据库由PostgreSQL 转为Oracle 10g。由于之前的逻辑几乎都分布于存储过程,所以多代码的修改相对来说较小。因对Oracle 数组参数的转换花了些时间,所以记录下来,分享一下...
  • appllon
  • appllon
  • 2010年01月11日 12:46
  • 1588

Quake源代碼分析(草稿).1

        Quake是Id Software公司推出一款風迷全球的FPS遊戲.至今為止已經發展到了第三代,而且作為一個優良的遊戲引擎,它也被大量的運用到其他公司開發的遊戲當中.例如我們所熟知的C...
  • breakpointer
  • breakpointer
  • 2004年09月30日 09:40
  • 3069

EasyUI datagrid数据表格--获取datagrid中选中行的数据

1.原因:如图 当我点击附件下载时需要获取选中行的数据,从而对立面的附件字段进行判断,从而弹出提示框 2.代码 var row = $('#datagrid').datagrid('getSele...
  • muyeju
  • muyeju
  • 2015年08月13日 15:27
  • 3213

Quake源代碼分析(草稿).4

Quake網絡部分總結:(1) 網絡部分被分為接收和傳送兩個部分.(2) 傳送部份被分為本地數據包傳輸和異地數據包傳輸兩個部分.(3) 本地封包傳輸由NET_SendLoopbackPacket()負...
  • amdk_7
  • amdk_7
  • 2006年05月18日 14:30
  • 922

Quake源代碼分析(草稿).2

        在上一篇文章里,我談到過Quake的各個邏輯模塊被封裝在不同的DLL中,它們之間的交互利用了引出函數作為接口.這一點有點像COM,不同的是COM需要對DLL進行註冊,因為COM有時要提...
  • amdk_7
  • amdk_7
  • 2006年05月18日 14:24
  • 1018
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Quake源碼的一個參數引用技巧
举报原因:
原因补充:

(最多只允许输入30个字)