[英]fscanf read()s more than the number of characters I asked for
我有以下代碼:
#include <stdio.h>
int main(void)
{
unsigned char c;
setbuf(stdin, NULL);
scanf("%2hhx", &c);
printf("%d\n", (int)c);
return 0;
}
我將stdin
設置為無緩沖,然后讓scanf
讀取最多 2 個十六進制字符。 確實, scanf
確實按照要求進行了。 例如,將上面的代碼編譯為foo
:
$ echo 23 | ./foo
35
但是,如果我對程序進行strace
,我發現 libc 實際上讀取了 3 個字符。 這是來自 strace 的部分日志:
$ echo 234| strace ./foo
read(0, "2", 1) = 1
read(0, "3", 1) = 1
read(0, "4", 1) = 1
35 # prints the correct result
所以 sscanf 給出了預期的結果。 但是,可以檢測到這個額外的字符被讀取,它恰好破壞了我試圖實現的通信協議(在我的例子中,GDB 遠程調試)。
sscanf 的手冊頁說明了字段寬度:
當達到此最大值或找到不匹配的字符時,字符的讀取將停止,以先發生者為准。
至少,這似乎有點欺騙性。 或者它實際上是一個錯誤? 希望使用無緩沖的標准輸入,scanf 讀取的輸入量不會超過我要求的輸入量,這是否太過分了?
(我在 Ubuntu 18.04 和 glibc 2.27 上運行;我沒有在其他系統上嘗試過。)
至少,這似乎有點欺騙性。 或者它實際上是一個錯誤?
國際海事組織,沒有。
輸入項從 stream 中讀取,... 輸入項定義為輸入字符的最長序列,不超過任何指定的字段寬度,並且是匹配輸入序列或匹配輸入序列的前綴。 輸入項之后的第一個字符(如果有)保持未讀狀態。 如果輸入項的長度為零,則指令執行失敗; 這種情況是匹配失敗,除非文件結束、編碼錯誤或讀取錯誤阻止了來自 stream 的輸入,在這種情況下是輸入失敗。 C17dr § 7.21.6.2 9
諸如"%hhx"
類的代碼(沒有寬度限制)當然必須超過十六進制字符 1 才能知道它完成了。 多余的字符被推回stdin
以進行下一次輸入操作。
“輸入項后的第一個字符(如果有)仍未讀”對我來說意味着從最低級別的 stream 讀取字符和從 stream 讀取字符作為ZF7B44CFAFD -5C522212E7BZ 至少可以推回5C522212E7BZ8888將其視為“未讀”。 寬度限制 2 不保存代碼,因為可以從stream讀取 3 個字符並將 1 推回。
2 的寬度限制了要解釋的最大字節長度,而不是在最低級別讀取的字符數的限制。
希望使用無緩沖的標准輸入,scanf 讀取的輸入量不會超過我要求的輸入量,這是否太過分了?
是的。 如果緩沖與否,我認為像stdin
這樣的stream允許回推字符以認為它們未讀。
無論如何, "%2hhx"
是脆弱的,因為前導空格不計算在內,所以讀取的字符數不超過 2 個。 “這些空白字符不計入指定的字段寬度。”
“我將標准輸入設置為無緩沖”並不會阻止stream讀取多余的字符並稍后將其推回。
鑒於“可以檢測到正在讀取的這個額外字符,並且它恰好破壞了通信協議”,我推薦一種不使用stream的新方法。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.