C语言中的可变参数及宏定义使用分析

2014/05/0614:25:24 发表评论

今天看到了c语言的中可变参数宏定义,以前没见过,上网查了点资料,让我们先看看c语言中可变参数函数吧。下面是c语言中printf函数的声明

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

你可以看到printf的第二个参数是三个.,这就是c语言中的可变参数使用。那么我们如何定义我们自己的可变函数了,首先你要包含#include<stdarg.h>头文件来使用里面四个内置的宏,va_list, va_start, va_arg, va_end;下面定义定义一个我们自己的可变参数

#include <stdarg.h>
#include <stdio.h>

int add(int len, ...)
{
	int i = 0;
	int sum = 0;
	va_list va;
	va_start(va, len);
	for(i=0; i<len; i++)
	{
		sum += va_arg(va, int);
	}
	
	return sum;
}

int main(int argc, char* argv[])
{
	printf("add(5) = %d\n", add(5, 1, 2, 3, 4, 5));
	printf("add(3) = %d\n", add(3, 1, 2, 3));
	
	return 0;
} 

查看运行结果

上面的函数add函数式一个可变参数函数,第一个参数是固定,这个是定义一个可变参数的的必须条件,用于得到虚参在栈里面的首地址,函数的功能实现指定个整数的和,第一个参数指定数的个数。下面我们分析add函数,首先va_list声明一个变量,

va_list可能是这样一个#define va_list void*宏定义,

va_start可能是这样一个#define va_start(va, len) (va = (void*)((char*)&len + sizeof(len))),va_start宏是通过第一个固定参数len来给找到第一个可变参数(c语言中函数入栈是从右向左的)的地址,既va变量里面存放的就是我们第一个可变参数的首地址

va_arg可能是这样一个#define va_arg(va, int) *((int*)(va = (void*)((int*)va + 1)) - 1)宏定义,用于得到其中的某个变参的值

va_end可能是这样一个#define va_end(va) va = NULL;

经过我们上面的分析我们可以去掉我们第一次包含的#include <stdarg.h>头文件,所用我们自定义的宏,例如下面的代码:

#include <stdio.h>

#define va_list void*
#define va_start(va, len) (va = (void*)((char*)&len + sizeof(len)))
#define va_arg(va, int) *((int*)(va = (void*)((int*)va + 1)) - 1)
#define va_end(va) va = NULL;

int add(int len, ...)
{
	int i = 0;
	int sum = 0;
	va_list va;
	va_start(va, len);
	for(i=0; i<len; i++)
	{
		sum += va_arg(va, int);
	}
	
	return sum;
}
int main(int argc, char* argv[])
{
	printf("add(5) = %d\n", add(5, 1, 2, 3, 4, 5));
	printf("add(3) = %d\n", add(3, 1, 2, 3));
	
	return 0;
}

这次我们没有包含#include <stdarg.h>头文件,看看运行结果和上面的运行结果一致.

 

下面我们在来看看c语言中可变参数宏定义(不要第一个参数为固定参数,宏只是简单的文本替换),先来看看一个定义

#define LOG(arg...) printf("%s:%d:%s", __FILE__, __LINE__, arg),__FILE__和__LINE__是c语言中内置的宏,用于显示当前文件名和行号,这里我们使用了arg这个名字,如果在定义的时候没有写名字,例如像这样

#define LOG(...) printf("%s:%d:%s", __FILE__, __LINE__, __VA_ARGS__)我们可以使用__VA_ARGS__这个宏来代替

这里还有一个##号的用法,放在__VA_ARGS__的前面,例如像这样

#define LOG(...) printf("%s:%d:%s", __FILE__, ___LINE__, ##__VA_ARGS__), 当我们以LOG(); 调用时,会自动去掉__LINE__后面的逗号,下面是一个测试例子

#include <stdio.h>

#define LOG(arg...) printf("%s:%d:%s\n", __FILE__, __LINE__, arg)

int main(int argc, char* argv[])
{
	LOG("hello world!");
	
	return 0;
}

上面的运行结果是:

#include <stdio.h>

#define LOG(...) printf("%s:%ds\n", __FILE__, __LINE__, ##__VA_ARGS__)

int main(int argc, char* argv[])
{
	LOG();
	
	return 0;
}

上面的运行结果是:

上面这些是我个人对可变参数的理解,错误请大家指正。

  • 微信扫码赞助
  • weinxin
  • 支付宝赞助
  • weinxin

发表评论

您必须才能发表评论!