从管道读取输入时的scanf问题

3

我正在用C语言编写一个程序,试图创建一个自动化测试程序。将会派生一个进程,它的输入/输出通道(stdin、stdout和stderr)将被重定向到“黑盒测试模块”中。 假设有一个简单的程序,涉及两个数字的乘法。在这种情况下,要测试的程序如下:

#include<stdio.h>
int main()
{
    int a, b, numTc, i = 0; //numTc being the number of test cases
    scanf("%d",&numTc);
    for(;i < numTc; i++)
    {
        scanf("%d%d",&a,&b); //Facing issue here
        printf("%d\n",a*b);
    }
}

黑盒测试模块首先将此程序的I/O通道重定向到管道,然后使用write()系统调用先写入测试用例数量,然后是测试用例本身。

我面临的问题是: 像上面标记的第二个scanf会停顿。如果我构造整个输入缓冲区并在附加"\n"后将其写入管道,则一切正常运行。

但是,我想逐个实现功能。

以下是黑盒模块的逻辑:

  1. 从数据库中读取总测试用例数
  2. 构造一个输入缓冲区,其中所有测试用例都以空格分隔,并以换行符结尾。
  3. 将此缓冲区写入待测试进程的stdin
  4. 等待被测试进程输出。

以上工作正常。但是黑盒模块应该能够逐个编写测试用例。


1
通常更好的风格是写for (i = 0; i < numTx; i++),而不是在单独的声明中进行循环控制初始化。在C99中(你必须使用它,因为你没有从main()显式返回值),你可以写成for (int i = 0; i < numTc; i++) - Jonathan Leffler
1
在scanf中的两个%d之间加上一个空格。 - Keith Randall
2个回答

2

您是否想读取两个相邻的一位数字?如果是,您可以考虑使用%1d

有输入示例会很有帮助。


样例输入:2 3 4 5 6 其中,2表示测试用例的数量,后面跟着两组数字。因此输出结果为34=12和56=30。 - Cik
第一个“%d”将读取直到第一个不能成为其数字的字符(空格,换行符,一些数字后的减号等); 第二个“%d”将跳过前导空格并尝试将其后面的内容转换为另一个数字。如果发送的数字实际上是分开的,则“%d%d”没有实际问题。如果您需要读取两个单个数字,则确实需要考虑“%1d%1d”,但空格仍不是必需的,尽管它是传统的且更易于阅读。 - Jonathan Leffler

0

你的问题很可能是标准输入/输出到管道与标准输入/输出到终端的行为不同。当写入终端时,默认情况下是行缓冲;当写入管道时,则是完全缓冲。因此,在使用printf()后,你的程序需要fflush(stdout);来实际发送数据到管道。

严格来说,你应该检查scanf()的返回值,以确保你得到了预期的结果。如果第一个scanf()没有返回1或第二个没有返回2,那么就有问题了。

你可以通过打开日志文件来调试你的问题,以查看正在读取的内容。确保你也将输出刷新到该日志文件中。


我猜在这里刷新是没有办法的,因为进入for循环后,程序会在scanf调用中被阻塞住。 - Cik
@Cik:或许是,或许不是……如果这是循环的第一次迭代,也许不会出现这个问题,但我猜测是第二次迭代出现了问题,并且麻烦在于黑盒测试人员在写第二个问题之前等待第一个问题的答案。也就是说,输入将是一行中的2(表示要计算两个和)后面跟着3 4;程序读取输入,计算出结果12并进行printf()操作;然后回到等待下一个输入的状态,但测试人员在发送第二个计算所需的5 6之前正在等待看到12的输出结果。 - Jonathan Leffler

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接