可變參數列函式的原理及實現

2022-09-01 21:27:15 字數 2097 閱讀 9241

ansi c中庫函式printf的正確形式如下:

int printf(char *fmt, ...);

其中,省略號表示參數列的數量和型別是可變的。省略號只能出現在參數列的尾部。如何實現這樣乙個具有可變參數列的函式?在《the c programme language》中實現了這樣乙個示例函式:

void minprintf(char *fmt, ...);

先看看它的實現方式,然後研究下它的實現原理,函式minprintf只處理格式字串和引數,格式轉換則通過呼叫函式printf實現。

**

#include 

"stdarg.h

"#include "stdio.h"

void

minprintf(

char

*fmt, ...)

switch

( *++

p )}

va_end(ap);

}

上述**中標準標頭檔案「stdarg.h」中包含一組巨集定義如下,它們對如何遍歷參數列進行了定義。該標頭檔案的實現因機器的不同而不同,但提供的介面是一致的。

typedef char* va_list;

void va_start ( va_list ap, prev_param ); /* ansi version */

type va_arg ( va_list ap, type );

void va_end ( va_list ap );

va_list 其實是乙個字元指標型別,**中宣告乙個變數。該變數將依次引用各引數。**中宣告此型別的變數為ap, 即「引數指標」。巨集va_start將ap初始化為指向第乙個無名引數的指標。第乙個引數是 ap 本身,第二個引數是在變參表前面緊挨著的乙個變數,即「...」之前的那個引數;在使用ap之前,該巨集必須被呼叫一次。參數列必須至少包括乙個有名引數(即「char *fmt」),va_start將最後乙個有名引數作為起點。

然後呼叫va_arg獲取引數,它的第乙個引數是ap,第二個引數是要獲取的引數的指定型別,然後返回這個指定型別的值,並且把 ap 的位置指向變參表的下乙個變數位置;

最後獲取所有的引數之後,我們有必要將這個 ap 指標關掉,以免發生問題,方法是呼叫 va_end,它將輸入的引數 ap 置為 null。

函式引數的傳遞原理

函式引數是以資料結構以棧的形式訪問,從右至左依次入棧。引數存放在記憶體的棧空間中,在執行函式的時候,從最後乙個開始入棧。棧底高位址,棧頂低位址,舉例如下:

對於函式 void foo(int x, float y, char z);

那麼,呼叫函式的時候,實參 char z 先進棧,然後是 float y,最後是 int x,因此在記憶體中變數的存放次序是 x->y->z(從低位址到高位址的順序),因此,只要知道任意乙個變數的位址,並且知道其他變數的型別(這樣才能正確的實現指標移位運算),可以順藤摸瓜找到其他的輸入變數。一段驗證性的示例**如下,輸出會為1,2,3,4,

**

void

fun(

inta, ...)

}int

main()

最後,利用可變參數列,實現乙個實踐中使用的函式:

int max(int n, ...); //此函式返回引數中最大的那個數值。

#include "stdarg.h"

#include "stdio.h"

#include "string.h"

int max(int n, ...)

va_end(ap); // 關閉 ap

return max_num;

}int main()

程式執行輸出 :  30   50  ,分別為兩個參數列中的最大值。

由於巨集定義來實現變長參數列,因此可能會出現這麼一些問題:

一. 由於是巨集實現,不會對引數型別進行檢查,引數很容易發生隱式的型別轉換獲取乙個值(譬如輸入乙個float,
卻以int型去型別轉化),這樣做會出現一些未曾預計的結果。
二. 引數指標移動時容易出現越界訪問,超出函式棧幀的實際範圍,可能導致程式崩潰的執行時結果。

系統參數列的設計

create table t systemprofile fsystemprofileid bigint not null,系統參數列id fcategory varchar 30 not null,類別 fkey varchar 30 not null,類別下的表示符號 fvalue nvarch...

可變引數的原理及實現方式

前幾天看見小夥伴們發了乙個面試題,題目是printf的可變引數是如何實現的?然後我就專門研究了一下,通過彙編可以知道他們的實現步驟。下面我們通過彙編來帶大家了解下他們的輸出結果到底是多少。printf int d,d n 10,a 彙編如下 通過彙編可以看出,printf是從右向左進行入棧的,a和1...

可變引數函式的基本原理及使用實現

本文主要介紹可變引數的函式使用,然後分析它的原理,程式設計師自己如何對它們實現和封裝,最後是可能會出現的問題和避免措施。va函式 variable argument function 引數個數可變函式,又稱可變引數函式。c c 程式設計中,系統提供給程式設計人員的va函式很少。printf scan...