C语言的sprintf和snprintf将变量格式化输出到内存buffer,其功能强大,用起来很方便。但sprintf系列函数的运行效率低下,主要包括四方面的原因:格式字符串解析、变参处理、locale(本地化)支持和通用(如对齐、填充、精度、宽度等)导致的复杂性。
在FastDFS和FastCFS项目中,我们将低效的sprintf和snprintf改造为高效的字符串拼接方式。因为C标准库没有提供itoa(整数转换为字符串)和ftoa(浮点数转换为字符串)这样的转换函数,我们在基础库libfastcommon中实现了fc_itoa、fc_ftoa和fc_ltostr_ex、int2hex和int2HEX等函数,这些函数均返回转换后的字符串长度。其中fc_itoa和fc_ftoa转换后的字符串不以'\0'结尾,而fc_ltostr_ex是fc_itoa的加强版,支持以'0'补齐长度,且转换后的字符串以'\0'结尾。
fc_itoa根据传入的整数大小折半查找确认输出的字符串长度,因此不需要传统的字符串逆转操作。经实测,性能大约是sprintf的6倍。
fc_ftoa支持小数点后的保留位数,和sprintf一样采用四舍五入的做法。经实测,fc_ftoa性能大约是sprintf的25倍。
int2hex转换为小写字母的十六进制字符串,而int2HEX转换为大写字母的十六进制字符串。int2hex系列函数支持前导'0'补齐,对应sprintf的格式修饰符为%0#x,其中#为对齐位数,比如 %08x。经实测,int2hex性能大约是sprintf的7倍。
为了提高替换sprintf和snprintf的代码改造效率,libfastcommon中还封装了如下函数:fc_combine_two_strings、fc_get_full_filename、fc_get_one_subdir_full_filename和fc_get_two_subdirs_full_filename等,欢迎大家观摩。
fc_itoa、fc_ftoa、fc_ltostr_ex和int2hex等转换函数在shared_func.h和shared_func.c中实现。fc_itoa、fc_ftoa、int2hex和sprintf的性能对比测试源码为 libfastcommon/src/tests/test_fast_buffer.c,感兴趣的朋友可以把玩一下。