最近在工作中,遇到一處 printf
輸出有null
的情況,在此記錄一下,問題分析的過程。
測試代碼很簡單,本機為64位操作系統:
#include <stdio.h>
#include <time.h>
int main(){
char addr[128] = "127.0.0.1";
printf("1. output: %s \n", addr);
printf("2. %ld output: %s \n", 100, addr);
printf("3. %ld output: %s \n", time(NULL), addr);
return 0;
}
輸出結果為:
前兩個很好理解,第三項輸出有 (null),這里就很奇怪了,后面的addr
變量沒有正確輸出。
繼續一些測試,
__time32_t test_time_t_32_return()
{
return 100;
}
__time64_t test_time_t_64_return()
{
return 100;
}
printf("__time32_t:%d __time64_t:%d\n", sizeof(__time32_t), sizeof(__time64_t));
printf("6. %ld output: %s \n", test_time_t_32_return(), addr);
printf("7. %ld output: %s \n", test_time_t_64_return(), addr);
上說結果表明:當time(NULL)
返回32位數時,printf輸出是正確的,返回64位數字時,輸出為空。
經過查找資料,得知printf
輸出格式化%ld
只能輸出32位數字,當輸入內容為64位數字時,應當會截取低32位,當做%ld
的輸入,而高32位內容為空,會傳遞給后一個參數%s
,當%s
接收到輸入0,會輸出(null).
下面經過一些實際代碼來驗證下:
__time64_t test = 0x12345678abcdabcd;
printf("7. low 32: %lx high 32: %lx\n", test);
printf("8. 64 interger: %llx \n", test);
printf("9: %s", 0);
輸出內容如下:
printf
輸出的格式控制字符,%lx
以16進制打印輸出32位數字,%llx
以16進制打印輸出64位數字。
printf
的格式控制字符,%s
在內部解析時,應該有判斷為空的情況,傳入為空字符串,會轉為輸出(null)
字符串。以上是猜測,讓我們深入源碼來了解下:
在windows
上,VC編譯器會附帶C標准庫的實現,通過查找,初步定位在D:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\crt\src\printf.c
文件中,將此文件拉入VS2010
,在printf
函數的入口處打上斷點,開啟調試就可以進入源碼調試。
我們本次的興趣點在輸出(null)
的情況,因此,直接跟進去查找(null)
字符串出現和使用的地方即可:
空字符串定義如下圖:
空字符串轉換如下圖:
小結:打印輸出時,注意32位整數和64位整數的打印方式區分。