scanf读取管道输入首值不符合预期:无法读取为整数
问题分析与解决
你的核心问题大概率是第一个程序(prog1)的输出包含终端控制字符(比如颜色代码),这些字符在终端中会被解析为格式控制,不会显示,但通过管道传递给prog2时,会被当作普通输入数据,导致scanf("%d")无法匹配第一个字段(因为字段开头不是纯数字),而%s会把控制字符和数字一起读成字符串。
验证方法
先确认prog1的输出是否有隐藏字符:
./prog1 | cat -A
如果输出中出现类似^[[32m(ESC开头的序列),就说明存在终端控制字符。
解决方案
1. 修复prog1的输出逻辑
让prog1只在输出到终端时才输出控制字符(比如颜色),管道输出时输出纯文本:
#include <unistd.h> // 引入isatty函数 // 替换原printf代码 int is_term = isatty(STDOUT_FILENO); if (is_term) { // 如果是终端,保留原有的带格式输出(比如颜色) printf("\033[32m%d %zu.%-6zu %d %3d %9d\033[0m\n", 1, event1.time.tv_sec, event1.time.tv_usec, event1.type, event1.code, event1.value); } else { // 管道输出时,只输出纯文本 printf("%d %zu.%-6zu %d %3d %9d\n", 1, event1.time.tv_sec, event1.time.tv_usec, event1.type, event1.code, event1.value); }
2. 更可靠的prog2解析方式
不管prog1的输出有没有问题,用fgets读取整行再解析,比直接用scanf更稳定,还能避免输入缓冲的问题:
#include <stdio.h> int main() { char line[256]; int event_num, type, code, value; long sec, usec; // 用整数存储秒和微秒,避免double精度问题 while (fgets(line, sizeof(line), stdin) != NULL) { // 解析整行数据,拆秒和微秒为整数 int ret = sscanf(line, "%d %ld.%ld %d %d %d", &event_num, &sec, &usec, &type, &code, &value); if (ret == 6) { double time = sec + usec / 1000000.0; // 正常处理数据,比如打印验证 printf("Parsed: %d, %.6f, %d, %d, %d\n", event_num, time, type, code, value); } else { fprintf(stderr, "Invalid input line: %s", line); } } return 0; }
额外说明
- 你之前尝试的
%[^0-9]%d格式不适用,因为如果第一个字符就是数字,%[^0-9]会匹配失败,导致整个scanf返回0。 - 直接读取
double类型的时间可能存在精度损失,拆分秒和微秒为整数再计算更准确。
内容的提问来源于stack exchange,提问作者Clay Smith
相关产品推荐
相关产品推荐

