1、什麼是可變參數編程

在C語言編程中有時會遇到一些參數個數可變的函數,例如printf(),scanf()函數,其函數原型爲:函數

int printf(const char* format,)
int scanf(const char *format,)

它除了有一個參數format固定之外,後面跟着的參數的個數和類型是可變的(用三個點「…」作參數佔位符)post

2、簡單的可變參數例子spa

#include <stdio.h> #include <stdarg.h> 
void print_args(int count, ...);

int main(int argc, char* argv[]) {
	print_args(5,1,2,3,4,5);
	return 0; 
}

void print_args(int count, ...) {
	int i, value;
	va_list arg_ptr;
	va_start(arg_ptr, count);
	for(i=0; i<count; i++) {
		value = va_arg(arg_ptr,int);
		printf("position %d = %d\n", i+1, value);
	}
	va_end(arg_ptr);
}

3、對va_arg,va_list,va_start,va_end剖析.net

可變參數用到如下宏函數:指針

原型: void va_start(va_list arg_ptr, prev_param); 功能:以固定參數的地址爲起點肯定變參的內存起始地址,獲取第一個參數的首地址code

返回值:無orm

原型:va_list 類型的變量,va_list arg_ptr ,這個變量是指向參數地址的指針,由於獲得參數的地址以後,再結合參數的類型,才能獲得參數的值。blog

原型:type va_arg(va_list arg_ptr, type); 功能:獲取下一個參數的地址 返回值:根據傳入參數類型決定返回值類型內存

原型:void va_end(va_list arg_ptr); 功能:將 arg_ptr 指針置0 返回值:無

對應於上面的實例,參見下面的示意圖,便可明白,

|   5	|		|   5	|		/\	|   5	| <--arg_ptr
|   4	|		|   4	|		||	|   4	|
|   3	|		|   3	|		||	|   3	|
|   2	|		|   2	|		||	|   2	| 
|   1	|		|   1	| <-- arg_ptr	||	|   1	|
|   5	|   <-- count 	|   5	|   <-- count	||	|   5	|   <-- count

這三個宏的實現細節,可參見下面的 blog:

[1] C中可變參數函數實現

[2] 內存對齊 _INTSIZEOF(n)