文档章节

函数可变参数

abcijkxyz
 abcijkxyz
发布于 2016/11/22 16:46
字数 877
阅读 9
收藏 0

程序debug过程中经常会打印调试信息,如果我们要在程序运行过程当中看到调试信心,就得把运行的状态信息输出到文件。于是,我写了下面两个函数来实现可变参数的打印调试信息到文件。

 

#include "stdio.h"
#include "stdarg.h"

 

int print_string_to_file(char file_name[64], ...)
{
 va_list ap;
 char *p;
 FILE* fp;

 fp = fopen(file_name, "ab");
 if (fp == NULL)
 {
  return -1;
 }


 va_start(ap, file_name);
 p = va_arg(ap, char *);

 while (p != NULL)
 {
  fprintf(fp, "%s/n", p);
  p = va_arg(ap, char*);
 }
 va_end(ap);
 fclose(fp);
 return 0;
}

 

 

static char szBuffer[8*1024];

 

int print_data_to_file (char file_name[64], const char * szFormat, ...)
{
 int     iReturn ;
 va_list pArgs ;
 FILE* fp;

 fp = fopen(file_name, "ab");
 if (fp == NULL)
 {
  return -1;
 }

 va_start (pArgs, szFormat) ;
 iReturn = vsprintf (szBuffer, szFormat, pArgs) ;
 fprintf(fp, "%s",szBuffer);
 va_end (pArgs) ;
 fclose(fp);
 return iReturn ;
}

 

其中,第一个函数只能打印字符串,并且调用的时候最后一个参数必须传入一个NULL指针,从里面的代码也可以看到可变参数的实现技巧。

而第二个函数可以按照格式化的信息打印,类似于printf的format。简单的调用代码如下:

 

 

 

int main(int argc, char* argv[])
{

 float f = 7.0f;

 

 print_string_to_file("info.txt", "123","string", NULL);


 print_data_to_file("info2.txt","str = %s, float num = %f/n", "string", f);


 return 0;

 

 

 可变参数的函数实现实际上与函数参数传递的堆栈结构有关,在x86平台,一般的c编译器的参数传递默认按照从右到左的,即函数中的最右边的参数最先入栈的顺序。这个实际上与调用约定有关。对于函数

 

void fun1(char a, int b, double c, short d) ;

 

 

如果知道了参数a的地址,则要取后续参数的值则可以通过a的地址计算a后面参数的地址,然后取对应的值,而后面参数的个数可以直接由变量a指定,当然也可以像printf一样根据第一个参数中的%模式个数来决定后续参数的个数和类型。如果参数的个数由第一个参数a直接决定,则后续参数的类型如果没有变化并且是已知的,则我们可以这样来取后续参数, 假定后续参数的类型都是double;

 

 

void fun1(int num, ...)
{
    double *p = (double *)((&num)+1);
    double Param1 = *p;
    double Param2 = *(p+1);
    ...
    double Paramn  *(p+num);
}

 

如果后续参数的类型是变化而且是未知的,则必须通过一个参数中设定模式来匹配后续参数的个数和类型,例如printf就是这样.

 

综上,我实现了一个求解n个整数的最大值的可变参数函数。

 

 

int Max(int n, ...)
{
    int *p = &n + 1;
    int ret = *p;
    for (int i=0; i<n; i++)
    {
        if (ret < *(p + i))
            ret = *(p + i);
    }
    return ret;
}


调用方式如下:

 

 

int main(int argc, char* argv[])
{

 int m3 = Max_num(3, 45, 12, 56);
 int m1 = Max_num(1, 3);
 int m2 = Max_num(2, 23, 45);

 int first = 34, second = 45, third=5;
 int m5 = Max_num(5, first, second, third, 100, 4);

}

 

 

 结论

  对于可变参数函数的调用有一点需要注意,实际的可变参数的个数必须比前面模式指定的个数要多,或者不小于, 也即后续参数多一点不要紧,但不能少, 如果少了则会访问到函数参数以外的堆栈区域,这可能会把程序搞崩掉。前面模式的类型和后面实际参数的类型不匹配也有可能造成把程序搞崩溃,只要模式指定的数据长度大于后续参数长度,则这种情况就会发生。

 

本文转载自:http://www.cnblogs.com/celerychen/archive/2011/06/30/3588218.html

共有 人打赏支持
abcijkxyz
粉丝 63
博文 6196
码字总数 1876
作品 0
深圳
项目经理

暂无文章

设计模式之 明确责任 观察者模式 状态模式 责任链模式

观察者模式是任务分发的一种模式。 如果认为我们设计的系统的各个模块(或子系统)的最终目的是完成共同任务,那么这个任务如何分配到多个模块的就是我们遇到的第一个问题。简单设计场合我们...

backbye
13分钟前
2
0
14-利用思维导图梳理JavaSE-大汇总

14-利用思维导图梳理JavaSE-Java基础知识大汇总 主要内容 1.对象入门 2.一切都是对象 3.程序流程控制 4.初始化和消除 5.权限访问控制 6.复用类 7.多态 8.接口与抽象类 9.内部类 10.容器 11.异...

飞鱼说编程
48分钟前
5
0
利用Lombok编写优雅的spring依赖注入代码,去掉繁人的@Autowired

大家平时使用spring依赖注入,都是怎么写的? @Servicepublic class OrderService { @Autowired private UserService userService;} 是不是很熟悉的感觉?但是呢 如果你用...

HeyS1
55分钟前
23
0
IBATIS 写BLOB字段遇到的问题

1、 首先遇到的配置问题,通过设置typeHandler 来支持写入。接下来由此引出了事务的问题。 <typeHandler jdbcType="BLOB" javaType="[B" callback="org.springframework.orm.ibatis.support....

echo-neo
今天
1
0
37. Sudoku Solver

Description tags: backtrack,hash table difficulty: hard Write a program to solve a Sudoku puzzle by filling the empty cells.A sudoku solution must satisfy all of the following......

52iSilence7
今天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部