标准输出重定向:改变输出的方向

6

我有一个名为abc的程序。

当我运行以下命令时:

$ ./abc < infile

我得到了以下输出:
ijklm

然而,当我运行以下命令时:
$ ./abc < infile > outfile
$ cat outfile

我将得到这个输出:
ijkoo

现在,我假设这是我程序中的一个错误。然而,无论我的程序在做什么,我都不知道这是如何可能发生的。

编辑:

既然我知道这是可能的,我很想知道是我的程序中的哪一部分导致了这种情况。

我的程序中有一个包含以下内容的循环内部块:

byte = ascii_to_byte(asciibyte);
putchar(byte);

byte是char类型。

现在,如果我将putchar(byte)更改为printf("%c", byte),则所有输出都保持不变。

但是,如果我将其更改为printf("%d", byte),那么$ ./abc < infile的输出如下:

105106107111111

这些ASCII字符在outfile中的十进制表示与它们实际发送到标准输出时的十进制表示不同。我不明白为什么会有这种差异。 编辑#2: 如果我将打印行更改为printf("%c\n", byte),那么$ ./abc < infile将输出:
i
j
k
o
o

这与输出到outfile的内容一致。再次说明不确定有什么区别。

编辑 #3

我在32位机器上进行了测试,程序可以正常运行:outputfile包含ijklm。奇怪。

编辑 #4

以下是主函数:

int main()
{
    char asciibyte[8];
    char byte;

    int c; //Using int to avoid the EOF pitfall.
    long charcount = 0;

    while((c = getchar()) != EOF){
        if(c != '0' && c != '1'){
            continue;
        }
        asciibyte[charcount % 8] = c;
        if(charcount % 8 == 7){
            /*Testing revealed that at this point asciibyte does contain
            what it should contain, eight ASCII ones and zeros representing
            a byte read in from stdin*/
            byte = ascii_to_byte(asciibyte);
            /*Print statements such as:
                printf("%d", byte);
                printf("%c\n", byte);
            reveal that the ascii_to_byte function works incorrectly on my
            64 bit machine. However these statements:
                putchar(byte);
                printf("%c", byte);
            make it appear as though the function operates as it should.
            EXCEPT if i redirect that output to a file.*/
            putchar(byte);
        }
        charcount++;
    }
    return 0;
}

以下是ascii_to_byte函数的代码:

char ascii_to_byte(char *asciibyte){
    char byte;
    int i;
    for(i = 0; i < 8; ++i){
        if(asciibyte[7-i] == '1'){
            byte = byte | (1 << i);
        }
    }
    return byte;
}

最终编辑

我注意到我应该将byte初始化为0x00。问题解决了。为什么我这么蠢?我会给那些能够具体解释这是如何导致问题的人答案分。


输出总是相同的吗?如果您运行./abc几次,是否会得到相同的结果? - Daren Thomas
是的,输出在多次试验中是一致的。 - oadams
./abc < infile | od -tx1 的输出是什么? - pmg
0000000 69 6a 6b 6f 6f 0000005 - oadams
此时,您需要开始缩小问题范围。理想情况下,您希望得到仅包含问题的单个代码页面,以便在此处发布。在修剪内容并将其替换为模拟版本的同时,要仔细观察可能具有副作用或可能超出缓冲区的任何内容。 - RBerteig
@oadams:尝试增加编译器的警告级别,看看它是否会“抱怨”一些相关的事情 :) - pmg
4个回答

3
这种奇怪的行为可能表明您的程序读取或写入了不应该的内存,随着代码其他部分对堆栈和/或堆的不同使用而改变。建议仔细检查代码是否存在缓冲区溢出、返回指向堆栈变量的指针等问题。通过调试器逐步执行代码可能会很有成效(但如果运气不好,也可能会改变其行为)。您看到了几件有趣的事情。
  1. 为什么重定向stdout可能会影响任何东西?也许是因为它导致C库的行为有些不同:流连接到终端设备或否决定了使用不同的缓冲模式(请参阅GNU libc documentation,或C99 §7.9.13 para. 7)。

  2. 为什么将putchar(byte)更改为printf("%c", byte)不会改变任何内容,而printf("%d", byte)printf("%c\n", byte)确实会改变行为?也许是因为编译器自动将printf("%c", byte)重写为更高效的putchar(byte) - 即使没有启用任何优化,较新版本的GCC通常会这样做 - 而printf("%d", byte)printf("%c\n", byte)真的会编译为对printf()的调用。


1

这是完全可能的 - 程序可以检查是否正在写入终端并写入与在写入管道时不同的内容。


1

正如你所说,byte未初始化,因此任何事情都有可能发生。

其中一个可能发生的事情是,byte从0“开始”,并保持它的值从函数调用到函数调用(就像它被声明为static一样)。

二进制表示...
byte | c (二进制) | byte | c -----------+--------------+-------------- 00000000 | i (01101001) | 01101001 (i) 01101001 | j (01101010) | 01101011 (k) * 奇怪,你得到了'j',但任何事情都有可能 :) 01101011 | k (01101011) | 01101011 (k) 01101011 | l (01101100) | 01101111 (o) 01101111 | m (01101101) | 01101111 (o)

0

尼尔·巴特沃斯说。该函数被称为 isatty

if (isatty(STDOUT)) printf("I am printing to the terminal!\n");

另外,在测试过程中,您可能已经完成了以下操作:

$ ./abc < infile > infile

不小心发生了。因此,您可能需要快速检查infile是否确实包含相同的数据。


是的,我已经用不同的测试输入做了很多次了,但还是很奇怪。 - oadams

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