採用c語言程式設計的時候,函式中形式引數的數目通常是確定的,在呼叫時要依次給出與形式引數對應的所有實際引數。但在某些情況下希望函式的引數個數可以根據需要確定。典型的例子有大家熟悉的函式printf()、scanf()和系統呼叫execl()等。那麼它們是怎樣實現的呢?
c編譯器通常提供了一系列處理這種情況的巨集,以遮蔽不同的硬體平台造成的差異,增加程式的可移植性。這些巨集包括va_start、va_arg和va_end等。在講解以上巨集之前我們先了解一下呼叫函式時傳入引數的處理過程。
一、函式傳入引數過程
乙個函式包括函式名、傳入引數、返回引數以及函式體,函式體編譯後的二進位制**儲存在程式**區。當使用者呼叫某個函式時,系統會通過函式名(c++中會涉及到mangled命名處理)查詢函式體入口指標並壓入棧中,之後將傳入引數以從右至左的順序壓入棧中(棧空間是往低位址方向增長的,也即棧底對應高位址,棧頂對應低位址),示例如下:
#include usingnamespace
std;
void fun(int
a, ...)
}int
main()
//output://1
//2//3
//4
二、va_start、va_arg和va_end巨集定義
接著我們再來看看va_start、va_arg和va_end等巨集的具體定義。
#define _intsizeof(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) ) //此句巨集的作用是將型別n的大小向上取成4的倍數,如n為char型的話結果即為4
#ifdef __cplusplus
#define _addressof(v) ( &reinterpret_cast(v) ) //
vs2015中此句高亮,作用是將v的位址重新解釋成char*型
#else
#define _addressof(v) ( &(v) )
#endif
#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 )#ifndef _va_list_defined
#ifdef _m_cee_pure
typedef system::argiterator va_list;
#else
typedef
char * va_list; //
vs2015中此句高亮
#endif /* _m_cee_pure */
#define _va_list_defined
#endif
//以上巨集定義出現在vadef.h,通過stdio.h即可使用
#define va_start _crt_va_start#define va_arg _crt_va_arg
#define va_end _crt_va_end
//以上巨集定義出現在stdarg.h中,若要使用則需加上 #include
三、va_start、va_arg和va_end使用示例
容易看出,以上巨集定義主要涉及位址操作,va_start獲取第二個傳入引數的位址給va_list型別變數(假設為arg_ptr),va_arg用於獲取當前引數值並將指標arg_ptr往後移,va_end則是將arg_ptr置為空。va_start、va_arg、va_end具體用法示例如下:
#include #includeint fun(int x, int
y) int fun(int
count, ...)
va_end(arg_ptr);
//將arg_ptr置為空
return
sum;
}int
main()
//output://0
//0//the 1 th arg: 2
//the 2 th arg: 3
//the 3 th arg: 4//7
注意:以上巨集操作並不提供引數個數獲取操作,這需要使用者在函式中獲取,如第二個fun函式使用count指明個數,printf通過解析第乙個傳入引數來確定引數個數與型別等。
Delphi深度探索
目錄 第一篇 com部分 1.1 activex部分 1.1.1 activex控制項之消失的事件 1.1.2 建立activex控制項之高階編輯介面 1.1.3 資料庫明了的activex控制項 1.2 基於com的office開發 1.2.1 office自動化程式設計 1.2.2 建立offi...
深度探索va start va arg va
採用c語言程式設計的時候,函式中形式引數的數目通常是確定的,在呼叫時要依次給出與形式引數對應的所有實際引數。但在某些情況下希望函式的引數個數可以根據需要確定。典型的例子有大家熟悉的函式printf scanf 和系統呼叫execl 等。那麼它們是怎樣實現的呢?c編譯器通常提供了一系列處理這種情況的巨...
Amazon Aurora 深度探索
amazon 的 aurora 自從問世,就備受關注,其效能和實現架構是被關注的熱點。2017年,amazon 發表了一篇 披露其實現的一些技術細節。本文在此背景下,對 aurora 系統的實現從整體架構 儲存 事務處理三個方面進行深入 並從資料庫核心技術實現的角度對 aurora 做了一定的推測。...