函数的可变参数在调试代码,输出关键变量值的实际应用

起因

今天在梳理日终结算平台的业务代码,整个系统基于MFC框架开发,对MFC的接触还要追溯到3年前读研期间的徐工项目,那段在徐工出差的日子也颇令人难忘。

项目比较古老,整个开发环境是vc6,由于对整个业务框架的不熟悉,以及对MFC的陌生,再加上对vc6环境的难以适应,我这只菜鸡只能想到,在相应的动作下fprintf一些重要的信息到文件中查看。但频繁的FILE *fp ,fopen 很烦(说实话 一遇到 c++ 文件操作 我就跳过,是该找时间复习一下c++的文件操作了)。

加上,每次想看的变量不同,所以联想到可变参数的使用,之前对此操作也只停留到了解,但并没有使用过,查找相关资料,自己写了一个logtest类。

用到的相关知识点:
函数的变参
获取本地时间
auto_ptr的使用 – (vc6.0 并不支持 c++11)

代码设计

言归正传,以下是logtest类的代码设计
logtest.h

#include <cstdio>
#include <memory>
class logtest
{
public:
    logtest(char *path = "");
    void createlog(char * contents,...);
    void overlog();
    ~logtest();
private:
    char * _path;//路径
    FILE * _fp;
};

logtest.cpp

#include "logtest.h"
#include <cstring>
#include <ctime>
#include <iostream>
#include <cstdarg>
logtest::logtest(char *path)
{
	//获取本地时间
    time_t t = time(0);
    char tmp[40]={NULL}; //40个字节 应该够了
    strftime(tmp, sizeof(tmp), "_%Y%m%d_%H_%M_%S",localtime(&t));
	
	//将本地时间与路径进行拼接
    _path = new char[strlen(path)+1+40];
    strcpy(_path,path);
    strcat(_path,tmp);


}

void logtest::createlog(char * contents,...)
{
    va_list ap;//可变参数列表 即 ...
    char *tmpAp;
    _fp = fopen(_path,"w+");

	//va_start 本质:从contents 开始 (不包含contents,) ...的第一个参数
    va_start(ap,contents);
    tmpAp = contents;// 保存第一个,第一个也是要输出的。

    while(tmpAp)
    {
        char * _text = new char[strlen(tmpAp)+1];
        //对于传入的内容不确定,我把分配的堆空间全部清0
        memset(_text,0,strlen(tmpAp)+1);
        strcpy(_text,tmpAp);
        fprintf(_fp,"%s\n",_text);
		//释放空间
        delete [] _text;
        _text = NULL;
        //va_arg 取得后一个参数 -- 这是错误的理解
        //参看va_arg(ap,v) 源码后,得到当前参数 的内容,但是ap已经指向了下一个参数 (*(char *)(arg+=4) -4);
        tmpAp = va_arg(ap, char*);
    }
    va_end(ap);
}

void logtest::overlog()
{
    fclose(_fp); //并没有丢到析构函数中,手动释放文件句柄,相对灵活一些。
}

logtest::~logtest()
{
   delete[] _path;
    _fp = NULL;
}

va_start,va_arg,va_end 必须配套使用。

坑一:va_start

va_start(ap,contents) 并不是从contents 开始,而是从contents 后一个参数开始。
之前参照的代码 大概的意思是,循环取 […] 中的参数,与contents进行拼接,而我的需求是 从contents开始,包括contents ,循环往文件中输出。

起初代码,createlog:

char * tmp;
va_start(ap,conntents);
while(tmp = va_arg(ap,char*))
{
...
}

所以 contents是无法操作的,如果对于 使用 createlog(test); 直接输出为空
对于使用 create(test,test2,NULL) 只能输出第二个test2

#include <iostream>
#include "logtest.h"


using namespace std;

int main(int argc, char *argv[])
{
    char * test = "for test1";
    char * test2 = "for test2";
    auto_ptr<logtest> ap(new logtest("C:\\FDlog\\debug"));//丢到智能指针里
    ap->createlog(test,test2);
    ap->overlog();
    return 0;
}

因为对业务的不熟悉,及对代码的陌生。并没有将释放文件句柄 放到析构函数中。
同时用智能指针管理 logtest对象,我想更为稳妥一些。

坑二: 哨兵 NULL

main函数测试

#include <iostream>
#include "logtest.h"


using namespace std;

int main(int argc, char *argv[])
{
    char * test = "for test1";
    char * test2 = "for test2";
    auto_ptr<logtest> ap(new logtest("C:\\FDlog\\debug"));
    //NULL 必不可少
    ap->createlog(test,test2,NULL);
    ap->overlog();
    return 0;
}

在调试的过程中,忘记在 createlog 成员函数中加入 NULL 哨兵,导致输出乱码。日终结算程序生成基金文件失败。(但并没有卡死,系统本身所出输出的日志文件缺失,只打印到数据库连接成功就结束)

在qt createor 4.01版本中测试:

  • ap->createlog(test) 是没有问题的

在vc6 环境中

  • ap->create(file_type) 是出现bug的
  • 必须加上NULL哨兵参数才可以

这周五晚上学习一下va_list、va_start、va_arg、va_end 的源码。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值