簡體   English   中英

fscanf read()s 超過了我要求的字符數

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM