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,感興趣的朋友可以把玩一下。