共计 2170 个字符,预计需要花费 6 分钟才能阅读完成。
今天看到了 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;
}
上面的运行结果是:
上面这些是我个人对可变参数的理解,错误请大家指正。
