我有以下代码:
#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函数的man文档关于字段宽度的说明如下:
当达到最大宽度或找到一个不匹配的字符时,字符读取将停止,以先发生的为准。
这似乎有点欺骗性,或者说这实际上是一个bug吗?希望使用非缓冲stdin时,scanf函数是否能够仅读取我请求的输入数量?
(我在运行Ubuntu 18.04和glibc 2.27;我还没有在其他系统上尝试过。)
scanf
、getc
、fread
等函数读取。 - Nate Eldredge