標籤:style blog io ar os 使用 sp for on
在C程式設計語言中,使用printf函數進行標準輸出。
int printf ( const char * format, ... );
printf函數申明中"..."代表可變參數。
printf ("floats: %4.2f %+.0e %E \n", 3.1416, 3.1416, 3.1416);printf ("Width trick: %*d \n", 5, 10);
那麼,如何?可變參數?
近日,在讀Linux0.12原始碼的過程中,我看到了一個實現。下面,我給出一個demo程式。
#include <iostream>using namespace std;typedef char *va_list;#define __va_rounded_size(TYPE) (((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int))#define va_start(AP, LASTARG) (AP = ((char *) &(LASTARG) + __va_rounded_size (LASTARG)))#define va_end(AP) #define va_arg(AP, TYPE) (AP += __va_rounded_size (TYPE), *((TYPE *) (AP - __va_rounded_size (TYPE))))void print_args(int args, ...){ va_list ap; //在訪問任何未命名的參數之前,必須用va_start宏初始化ap一次 va_start(ap,args); printf("%d\n",args); printf("%d\n",va_arg(ap,int)); printf("%s",va_arg(ap,char *));// va_end(ap);}int main(void){ int arg = 2; int args1 = 1; char *args2 = "abcdefg"; print_args(2,args1,args2); return 0;}
不妨在print_args程式中設定一個斷點。
首先,查看一下args參數的記憶體位址:
+&args0x0028f71cint *
現在,我們查看0x0028f71c處的記憶體:
0x0028F71C 02 00 00 00 ....0x0028F720 01 00 00 00 ....0x0028F724 08 58 cd 00 .X?.
顯然, 0x0028f71c處的4個位元組為0x00000002,即main函數中的arg參數;
0x0028f720處的4個位元組為0x00000001,即main函數中的args1參數;
而0x0028f724處的4個位元組內容為0x00cd5808,這是一個記憶體位址;
0x00CD5808 61 62 63 64 abcd0x00CD580C 65 66 67 00 efg.
繼續查看0x00cd5808處的記憶體,可以看出正是"abcdefg\0"。
有了上面的基礎,我們應當可以理解va_start, va_end和va_arg宏了。實際上,就是對地址的操作,以及強制類型轉換。printf函數也是利用上面3個宏實現可變參數功能的。
C可變參數實現原理