天天看点

开发那些事--不要过度依赖snprintf/sprintf开发那些事--不要过度依赖snprintf/sprintfsnprintf/sprintf性能问题snprintf/sprintf细节理解不够

将数据按照指定format输出到buffer中,往往会用snprintf/sprintf(推荐前者)。但各个场景都习惯性的用snprintf/sprintf却并不是什么好事。

在分析团队项目性能时候,发现将大量数据以文本text方式返回给客户端时,耗时非常多,且和类型有关,datetime > int > varchar。perf图分析后发现,snprintf占用了很多时间。因为datetime调用4次,int调用1次,varchar 0次。datetime和int类型调用都主要是将int转换为text文本方式。

对于int值打印,写ltoa函数和snprintf做性能对比。

o2编译执行,实验结果如下,ltoa性能是snprintf的1倍以上:

对于datetime类型,其实只是需要输出xxxx-mm-dd hh-mm--ss.uuuuuu格式的数据。要输出的位数已经确定,可以使用更简单的方式例如两位的moth/day,或者可能3位的数字:

上面的方式还需要做计算,如果使用200字节的字符串记录0~99的对应字符,那么对于2位数字的转换就可以直接用int64_t的赋值操作,性能对比代码如下:

得到性能结果,直接赋值的性能达到之前计算每个字符方式的4倍:

即用下面代码做替换可以得到更好的性能。

一个底层to_hex_str函数将输入指定data_length的in_data按字节转换为hex值,在下面的代码中检查buff_size至少是data_length的2倍,但是sprintf会在末尾补'0',会导致内存写越界。

一个类似to_hex_str的代码,使用如下方式打印。

这里就出现一个错误,in_buf是char,是有符号的,在使用%02x打印的时候,按整数方式打印,char的范围是[-128,127),但2个16进制仅能表示[0,255]。下面的例子中,buff中得到的就是ffffffff。其内容显然不是希望的。

这里如果使用snprintf,应该将char*转换为unsinged char* 。

实际上,每个字节打印16进制方式可以用如下代码:

snprintf/sprintf虽然用起来方便,但一定要分析好使用场景和功能,防止出现性能问题或者正确性问题。

继续阅读