文档章节

函数可变参数

abcijkxyz
 abcijkxyz
发布于 2016/11/22 16:46
字数 877
阅读 5
收藏 0
点赞 0
评论 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);

}

 

 

 结论

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

 

© 著作权归作者所有

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

暂无相关文章

JavaScript零基础入门——(八)JavaScript的数组

JavaScript零基础入门——(八)JavaScript的数组 欢迎大家回到我们的JavaScript零基础入门,上一节课我们讲了有关JavaScript正则表达式的相关知识点,便于大家更好的对字符串进行处理。这一...

JandenMa ⋅ 今天 ⋅ 0

sbt网络问题解决方案

转自:http://dblab.xmu.edu.cn/blog/maven-network-problem/ cd ~/.sbt/launchers/0.13.9unzip -q ./sbt-launch.jar 修改 vi sbt/sbt.boot.properties 增加一个oschina库地址: [reposit......

狐狸老侠 ⋅ 今天 ⋅ 0

大数据,必须掌握的10项顶级安全技术

我们看到越来越多的数据泄漏事故、勒索软件和其他类型的网络攻击,这使得安全成为一个热门话题。 去年,企业IT面临的威胁仍然处于非常高的水平,每天都会看到媒体报道大量数据泄漏事故和攻击...

p柯西 ⋅ 今天 ⋅ 0

Linux下安装配置Hadoop2.7.6

前提 安装jdk 下载 wget http://mirrors.hust.edu.cn/apache/hadoop/common/hadoop-2.7.6/hadoop-2.7.6.tar.gz 解压 配置 vim /etc/profile # 配置java环境变量 export JAVA_HOME=/opt/jdk1......

晨猫 ⋅ 今天 ⋅ 0

crontab工具介绍

crontab crontab 是一个用于设置周期性被执行的任务工具。 周期性执行的任务列表称为Cron Table crontab(选项)(参数) -e:编辑该用户的计时器设置; -l:列出该用户的计时器设置; -r:删除该...

Linux学习笔记 ⋅ 今天 ⋅ 0

深入Java多线程——Java内存模型深入(2)

5. final域的内存语义 5.1 final域的重排序规则 1.对于final域,编译器和处理器要遵守两个重排序规则: (1)在构造函数内对一个final域的写入,与随后把这个被构造对象的引用赋值给一个引用...

江左煤郎 ⋅ 今天 ⋅ 0

面试-正向代理和反向代理

面试-正向代理和反向代理 Nginx 是一个高性能的反向代理服务器,但同时也支持正向代理方式的配置。

秋日芒草 ⋅ 今天 ⋅ 0

Spring 依赖注入(DI)

1、Setter方法注入: 通过设置方法注入依赖。这种方法既简单又常用。 类中定义set()方法: public class HelloWorldOutput{ HelloWorld helloWorld; public void setHelloWorld...

霍淇滨 ⋅ 昨天 ⋅ 0

马氏距离与欧氏距离

马氏距离 马氏距离也可以定义为两个服从同一分布并且其协方差矩阵为Σ的随机变量之间的差异程度。 如果协方差矩阵为单位矩阵,那么马氏距离就简化为欧氏距离,如果协方差矩阵为对角阵,则其也...

漫步当下 ⋅ 昨天 ⋅ 0

聊聊spring cloud的RequestRateLimiterGatewayFilter

序 本文主要研究一下spring cloud的RequestRateLimiterGatewayFilter GatewayAutoConfiguration @Configuration@ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMi......

go4it ⋅ 昨天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部