C語言可變引數研究

2021-06-01 01:42:30 字數 2312 閱讀 5942

一. 何謂可變引數

int printf( const char* format, ...);

這是使用過c語言的人所再熟悉不過的printf函式原型,它的引數中就有固定引數format和可變引數(用」…」表示). 而我們又可以用各種方式來呼叫printf,如:

printf("%d",value);

printf("%s",str);

printf("the number is %d ,stringis:%s", value, str);

二.實現原理

c語言用巨集來處理這些可變引數。這些巨集看起來很複雜,其實原理挺簡單,就是根據引數入棧的特點從最靠近第乙個可變引數的固定引數開始,依次獲取每個可變引數的位址。下面我們來分析這些巨集。在vc中的stdarg.h標頭檔案中,針對不同平台有不同的巨集定義,我們選取x86平台下的巨集定義:

typedef char *va_list;

/*把va_list被定義成char*,這是因為在我們目前所用的pc機上,字元指標型別可以用來儲存記憶體單元位址。而在有的機器上va_list是被定義成void*的*/

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

/*_intsizeof (n)巨集是為了考慮那些記憶體位址需要對齊的系統,從巨集的名字來應該是跟sizeof(int)對齊。一般的sizeof(int)=4,也就是引數在記憶體中的位址都為4的倍數。比如,如果sizeof(n)在1-4之間,那麼_intsizeof(n)=4;如果sizeof(n)在5-8之間,那麼 _intsizeof(n)=8。*/

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

/*va_start 的定義為 &v+_intsizeof(v) ,這裡&v是最後乙個固定引數的起始位址,再加上其實際占用大小後,就得到了第乙個可變引數的起始記憶體位址。所以我們執行va_start (ap, v)以後,ap指向第乙個可變引數在的記憶體位址*/

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

/*這個巨集做了兩個事情,

①用使用者輸入的型別名對引數位址進行強制型別轉換,得到使用者所需要的值

#defineva_end(ap) ( ap = (va_list)0 )

/*x86 平台定義為ap=(char*)0;使ap不再指向堆疊,而是跟null一樣.有些直接定義為((void*)0),這樣編譯器不會為va_end產生**,例如gcc在linux的x86平台就是這樣定義的. 在這裡大家要注意乙個問題:由於引數的位址用於va_start巨集,所以引數不能宣告為暫存器變數或作為函式或陣列型別. */

以下再用圖來表示:

|最後乙個可變引數 | ->高記憶體位址處

|第n個可變引數 |->va_arg(arg_ptr,int)後arg_ptr所指的地方,

| | 即第n個可變引數的位址。

|第乙個可變引數 | ->va_start(arg_ptr,start)後arg_ptr所指的地方

| | 即第乙個可變引數的位址

|最後乙個固定引數 | -> start的起始位址

|——————————————— |-> 低記憶體位址處

三.printf研究

下面是乙個簡單的printf函式的實現,

#include "stdio.h"

#include "stdlib.h"

void myprintf(char* fmt, ...) //乙個簡單的類似於printf的實現,//引數必須都是int 型別

else

parg += sizeof(int); //等價於原來的va_arg

} ++fmt;

}while (*fmt != '\0');

parg= null; //等價於va_end

return;}

int main(int argc, char* argv)

在intel+win2k+vc6的機器執行結果如下:

the first test:i=1234

the secend test:i=1234; 0xabcd;j=5678;

四.應用

求最大值:

#include //不定數目引數需要的巨集

int max(int n,int num,...)

va_end(x);//清除變數x

return m;}

main()

c可變引數研究

們知道va start,va arg,va end是在stdarg.h中被定義成巨集的,由於1 硬體平台的不同 2 編譯器的不同,所以定義的巨集也有所不同,下 面以vc 中stdarg.h裡x86平台的巨集定義摘錄如下 號表示折行 typedef char va list define intsiz...

可變引數研究

可變引數的研究,可變引數底層是陣列,確定這個結論之後要實際驗證測試 package day9yue1 public class test1 如果這2個方法都叫test,編譯錯誤,說明引數是一模一樣,沒有過載 結論 string s 和 string.s 結果是一樣的 public void test...

c語言中關於可變引數的研究

include include void printlines char first,while str null va end v1 int main int argc,char argv 函式如何定義可變引數 eg void printlines char first,用三個點來代表可變引數函式...