printf可变形参的陷阱

有个程序的bug昨天晚上查了一晚上。

在程序中我使用了一个支持可变形参的logger。

可变形参就是C语言中的printf(const char* fmt, ...)这类的函数。

但是在程序运行的时候core dump。

bug是这样的,某个文件里面有一个字符串是这样的,"40%slik60%milk"。

读进来之后就成了string s("40%slik60%milk");

然后在某个debug的语句中,有LogDebug(s);

你就发现显示的结果是莫名其妙的。

原因见如下例子:

#include <iostream>
#include <string>
#include <stdio.h>
using namespace std;
int main()
{
    const char *a = "a[helloworld]\n";
    printf(a);
    //const char *b = "b[%s]\n";
    const char *b = "40%smilk60%silk";
    printf(b);
    return 0;
}

运行的结果如下:

a[helloworld]
4040404040404040milk60ilk

其实这个程序在编译的时候编译器就会给出警告(因为这里的字符串是写死在程序里的,如果是运行时载入的编译器就无能为力):

warning: format not a string literal and no format arguments [-Wformat-security]


其实本质就是一个原因,可变形参是

va_list和vsnprintf

之类的宏定义来实现的,通过运行时指针的偏移来获得函数的若干个可变形参。

但是这里的隐患就是,当printf的第一个形参format里面含有%的时候,即使printf只有一个形参,

在运行时vsnprintf之类的东西都会去通过指针的偏移来获取函数可变形参,这就会出现未定义的行为,就像刚才的结果。


突然间就明白了为什么C++的cin没有支持这种可变形参的函数形式,我想可能就是有这类隐患的原因吧。


对于此类问题,暂时我能想到的解决办法就是在使用这类可变形参的函数时候一定要小心。

即最好使用至少两个形参的形式。

如下:

#include <iostream>
#include <string>
#include <stdio.h>
using namespace std;
int main()
{
    const char *a = "a[helloworld]\n";
    printf("%s",a);
    //const char *b = "b[%s]\n";
    const char *b = "40%smilk60%silk\n";
    printf("%s",b);
    //cout<<b<<endl;
    return 0;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值