在学习Linux c编程中遇到了open函数 int open(const char *pathname, int flag, ... )
open函数根据是否传入第三个参数进行不同的操作,
现在我想自己编写一个函数 int va_fun(const char *str, int n, ... ),如果只有两个参数传入(va_fun(str,n)),则返回1,如果有第三个参数传入(va_fun(str,n,int_the_third)),则返回2,但我却不知道如何实现,希望会的好心人能给点提示。
我曾经尝试了如下代码:
#include<stdio.h>
#include<stdarg.h>
char *va_fun(const char *s,int n,...)
{
va_list ap;
int a;
va_start(ap,n);
if(a=va_arg(ap,int))
{
return "do it";
}
else
{
return "==";
}
va_end(ap);
}
void IntegerVarArgFunc(int i, ...){
va_list pArgs;
va_start(pArgs, i);
int j = va_arg(pArgs, int);
va_end(pArgs);
printf("i=%d, j=%d\n", i, j);
}
int main()
{
puts(va_fun("a",1));
puts(va_fun("a",1,2));
IntegerVarArgFunc(1);
IntegerVarArgFunc(1,2);
IntegerVarArgFunc(1,2,3);
return 0;
}
但是这样做却不管用,请问正确的做法如何?
(以上代码的输出是:
do it
do it
i=1, j=-157228448 //j是随机值
i=1, j=2
i=1, j=2)
这个就是C语言函数可变参数的实现。
man va_arg 可得详细的帮助信息。
看起来你还没有搞清楚c语言的可变参数的机制,那我就多说几句吧。
要搞清楚这一点,需要了解一些预备知识点:
C语言函数调用机制
程序进程运行时的内存分为5种:
函数调用时,先把调用方的返回地址(下一条指令)压栈,接着把被调用函数的实参压栈,最后再把被调用函数的局部变量压栈。
然后就把控制权交给了被调用函数(跳转到被调用函数的入口处指令开始执行)。
待函数执行完毕以后,先把函数的返回值放入寄存器,然后把局部变量弹栈、把函数的实参弹栈、把函数返回地址弹栈并跳转回该地址继续执行。也就返回了调用函数。
常见的调用机制有几种:
va_arg可变参数机制
可变参数函数的定义,一般具有如下形式:
在这里,va_list、va_start、va_end、va_arg(还有一个va_copy),其实都是一些宏定义。它们的作用如下:
这里有两个问题必须在调用方和被调用方之间实现协调好:
问题一:总共有几个可变参数?
要解决这个问题,一般有两种方法:
一种方法是像printf那样,利用固定参数来表明后续有几个可变参数,例如:
可以看到,在可是字符串里,通过占位符(%?)与可变参数一一对应,这样个数就明确了。
另一种方法是通过一个事先约定好的特殊值,表示可变参数的结束,例如:
这里通过一个特殊值(-1),表示后面没有可变参数了。
问题二:每个可变参数的类型分别是什么?
要解决这个问题,同样有两种方法:
一种方式仍然是像printf那样,通过固定变量明确每个可变参数的类型(比如:%s为字符串、%d为int、%ld为long int、%lld为long long int等)。注意:%c对应的可变参数仍然是int,而不是char,因为编译器默认会对代码做优化,内存地址对齐。
另一种方式,就是约定所有可变参数都是同样的类型。如上例的sum。
例程
把上面两个例子简单写一下:
运行结果如下: