logcpp自定义封装库多占位符参数拼接问题(printf,vprintf,sprintf,vsprintf对比)

  • 自定义封装前首先了解几个函数的原理

  1. int printf(char *format [,argument,…]); //输出到标准输出流

最基础的将占位符替换为变量后输出到标准输出流中

  1. int vprintf(const char * format, va_list arg args); //将变长参数拼接好之后输出到标准输出流

仔细思考一下作为printf的参数是一个变长的不可控数量的参数,因此再函数实现中想要完整的获取到参数就需要使用到va_list

va_list是在C语言中解决变参问题的一组,变参问题是指参数的个数不定,可以是传入一个参数也可以是多个;

可变参数中的每个参数的类型可以不同,也可以相同;

可变参数的每个参数并没有实际的名称与之相对应,用起来是很灵活。

va_list表示可变参数列表类型,实际上就是一个char指针fmt

  • 读到这里就可以开始自己试着封装自己的printf()函数了,下面是一个实例函数:

int LogPrint::printStr(const char *fmt, ...) const
{
    struct timeval tv;
    gettimeofday(&tv, nullptr);
    struct tm *lt = localtime(&tv.tv_sec);

    int ret = 0;

    ::printf("[%04d-%02d-%02d %02d:%02d:%02d:%03ld] ", //注意末尾保留一个空格
             lt->tm_year + 1900,
             lt->tm_mon + 1,
             lt->tm_mday,
             lt->tm_hour,
             lt->tm_min,
             lt->tm_sec,
             tv.tv_usec / 1000);

    va_list args;
    va_start(args, fmt);
    ret = vprintf(fmt, args); // to stdout
    va_end(args);

    return (logHeaderLength_ + ret);
}

这样就可以轻松的自定义一个带时间戳的打印函数了

  1. int sprintf(char *string, char *format [,argument,…]);'

sprintf();函数的用法比前面两个函数高级了一些,它可以把你想要打印的带占位符的字符串,还有多个可变参数,最终输出到一个字符串指针中,这样我们就可以不用输出到标准输出流,可以随意使用此函数进行字符串的格式化。

得到组合完成的字符串,想干啥干啥

  1. int vsprintf( char *buffer, char *format, va_list arg_ptr );

此函数结合了vprintf()和sprintf(),再这三个参数中,它可以把format字符串与后面的va_list中的变长参数整合后最终将整合好的字符串,整个的输出给buffer中,这样我们就得到了一个整合了变长参数,占位符合并完毕后的一个字符串,此时真的是想干啥干啥

  • 编码中的实际bug

log4cpp::Category &root_;
void EmsLog::debug(const char *fmt, ...)
{
    char strMsg[4096];
    va_list args;
    va_start(args, fmt);
    sprintf(strMsg,fmt, args); 
    root_.debug(strMsg);
}
//此函数目的是想整合变长参数到一个字符串中然后交给log4cpp中的接口去处理,很明显这样写bug有很多就不一一分析了
  • 修复版本

void EmsLog::debug(const char *fmt, ...)
{
    char strMsg[4096];
    int ret = 0;
    //格式化拼接
    va_list args;
    va_start(args, fmt);
    ret = vsprintf(strMsg,fmt, args); 
    va_end(args);
    //传出
    if(ret <= 4096){
        strMsg[ret] = '\0';
        root_.debug(strMsg);
    }
}

😄一开始拿到bug代码一脸懵,后来通过段错误的反馈,以及同事江哥的指导下找到了这几个函数之间细微的区别,sprintf()与vsprintf()只是相差了一个字母,但足以让项目崩掉,c++编码还是要细,越是大佬越是注重细节。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值