stdout перенаправление изменения выхода - PullRequest
6 голосов
/ 24 мая 2011

У меня есть программа с именем abc.

Когда я запускаю следующую команду:

$ ./abc < infile

Я получаю следующий вывод:

ijklm

Однако, когда я запускаю:

$ ./abc < infile > outfile
$ cat outfile

Мне выдается такой вывод:

ijkoo

Теперь я предполагаю, что это ошибка моей программы.Однако, независимо от того, что делает моя программа, я не знаю, как это возможно.

РЕДАКТИРОВАТЬ:

Теперь, когда я знаю, что это возможно, яЛюбопытно, что именно в моей программе вызывает это.

В моей программе есть блок, который содержит:

byte = ascii_to_byte(asciibyte);
putchar(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.Опять же, не уверен, в чем разница.

EDIT # 3

Я только что проверил это на 32-битной машине, и программа работает: outputfile содержит ijklm.Wierd.

EDIT # 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;
}

ЗАКЛЮЧИТЕЛЬНОЕ РЕДАКТИРОВАНИЕ

Я заметил, что должен был инициализировать байт до 0x00.Задача решена.Почему я отсталый?Я дам ответы на вопросы тем, кто может конкретно объяснить, как это вызвало проблему.

Ответы [ 4 ]

3 голосов
/ 24 мая 2011

Такое странное поведение, которое возникает и происходит в соответствии с кажущимися не связанными изменениями, вероятно, указывает на то, что ваша программа читает или записывает в память, чего не должно быть, и поведение меняется, поскольку другие части кода по-разному используют стек и / или куча.

Я бы тщательно проверил ваш код на наличие ошибок, таких как переполнение буфера, функции, которые возвращают указатели на переменные в стеке и т. Д.

Проход по коду с помощью отладчика может быть продуктивным (или он может снова изменить поведение, если вам не повезло!).

Есть пара интересных вещей, которые вы видели:

  1. Как перенаправление stdout может повлиять на что-либо? Возможно, потому что это приводит к тому, что библиотека C ведет себя немного по-другому: для потока используется другой режим буферизации, в зависимости от того, подключен он к терминальному устройству или нет (см. Документацию GNU libc или C99 §7.9.13, пункт 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 голос
/ 25 мая 2011

Как вы говорите, byte неинициализирован, поэтому может произойти все, что .

Одна из вещей, которая может произойти, это то, что byte "начинается" с 0 и сохраняетего значение от вызова функции до вызова функции (как если бы оно было объявлено static).

in binary ...

   byte    |    c (bin)   |   byte | c
-----------+--------------+--------------
 00000000  | i (01101001) | 01101001 (i)
 01101001  | j (01101010) | 01101011 (k) * strange you get 'j', but anything can happen :)
 01101011  | k (01101011) | 01101011 (k)
 01101011  | l (01101100) | 01101111 (o)
 01101111  | m (01101101) | 01101111 (o)
1 голос
/ 24 мая 2011

Это, безусловно, возможно - программа может проверить, пишет ли она в терминал, и записать что-то отличное от того, что она пишет при записи в канал.

0 голосов
/ 24 мая 2011

Что говорит Нил Баттерворт.Функция называется isatty.

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

Кроме того, во время тестирования вы могли бы сделать:

$ ./abc < infile > infile

случайно.Итак, вы можете быстро проверить, что infile действительно содержит те же данные.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...