C, K&R Упражнение 1–6, застрял, запутался

Я новичок, учусь программировать на C, используя Язык программирования C, второе издание (от K&R). В главе 1, раздел 1.5.1 Копирование файлов, авторы очень кратко касаются операционного приоритета при сравнении значений, подчеркивая важность использования круглых скобок в данном случае, чтобы гарантировать, что переменная 'c' перед оценкой сравнения. Они утверждают, что:

    c = getchar() != EOF

эквивалентно

    c = (getchar() != EOF)

Что "имеет нежелательный эффект установки c в 0 или 1, в зависимости от того, обнаружил ли вызов getchar конец файла"

Затем авторы ставят Упражнение 1–6. Убедитесь, что выражение getchar () != EOF равно 0 или 1.

Судя по предыдущему утверждению автора, это казалось почти тривиальным, поэтому я создал этот код:

#include <stdio.h>

main()
{
    int c;

    while (c = (getchar() != EOF))
        putchar(c);
}

К сожалению, когда я запускаю программу, она просто выводит любые символы, которые я ввожу в командное окно, а не ожидаемую строку 1 или 0, если встречается EOF.

Хотя я новичок, я думаю, что понимаю логику, которой пытаются научить авторы, и все же я не могу продемонстрировать эту простую задачу. В этом случае, не должна ли переменная c принимать значение, которое оценивается выражением сравнения, а не какой-либо символ getchar(), который может быть извлечен, особенно из-за расположения скобок? Если c действительно принимает значение сравнения, putchar() должен выводить только 0 или 1 и, тем не менее, как сформулировано, он выводит то, что я набираю в командном окне. Что я делаю неправильно? Что я не понимаю? Может быть, это мой компилятор? Я пишу код в Visual Studio 2017 Community edition в Windows 10 на архитектуре x64. У меня есть Tiny C Compiler, но я еще не пробовал запускаться из командной строки с TCC.


person H3G3moKnight    schedule 26.11.2017    source источник
comment
Целочисленные значения 0 или 1 на самом деле не являются печатаемыми символами ни в какой кодировке. Используйте, например, printf("%d\n", i) вместо этого.   -  person Some programmer dude    schedule 26.11.2017
comment
Может быть, OP видит все, что дает OP ... Да, это не что-то важное   -  person user2736738    schedule 26.11.2017
comment
Может ((c = getchar()) != EOF) ??   -  person David C. Rankin    schedule 26.11.2017
comment
Ребята. Я поражен вашей быстрой скоростью комментирования.   -  person iBug    schedule 26.11.2017
comment
И НЕТ, это не ваш компилятор. Убедитесь, что вы используете VS Developer Console и используете cl (cl.exe) из командной строки с минимальными параметрами cl /nologo /Wall /Ox /Feyourexe /Tc yoursource.c (вы можете добавить /Fo, например, /Foobjfile, чтобы указать имя объектного файла). Это помогает иметь подкаталоги obj и bin, чтобы сохранить ваш каталог файлов-ресурсов очистите и используйте /Foobj/thename /Febin/thename /Tc thename.c, чтобы поместить объектные файлы в подкаталог obj, а исполняемые файлы - в подкаталог bin. Удачи. (используйте /wd#### для подавления отдельных предупреждений)   -  person David C. Rankin    schedule 26.11.2017
comment
Я вставил этот код в среду mingw-gcc, изменил его на putchar(c?'1':'0'); и не получил результата. Я ставлю fflush(stdout); после putchar(), и тогда я вижу результат, но только после нажатия клавиши ввода. Я думаю, что реализации этой функции в POSIX могут отличаться от ожиданий авторов K&R.   -  person lockcmpxchg8b    schedule 26.11.2017
comment
@ lockcmpxchg8b Потому что вход и выход имеют строчную буферизацию.   -  person iBug    schedule 26.11.2017
comment
@ lockcmpxchg8b Значит, стандартные функции библиотеки C больше не работают так, как авторы K&R понимали бы их в свое время? Стандартные библиотеки действительно стандартны для платформы или они зависят от платформы?   -  person H3G3moKnight    schedule 26.11.2017
comment
@ H3G3moKnight Возможно, вы неправильно понимаете line-buffered.   -  person iBug    schedule 26.11.2017
comment
@Someprogrammerdude Это было полезно, спасибо.   -  person H3G3moKnight    schedule 26.11.2017
comment
@iBug: Думаю, я тоже недостаточно хорошо это понимаю. У вас случайно есть ссылка?   -  person lockcmpxchg8b    schedule 26.11.2017
comment
@ lockcmpxchg8b Уже есть один в Stack Overflow.   -  person iBug    schedule 26.11.2017
comment
@ lockcmpxchg8b И руководство GNU для libc.   -  person iBug    schedule 26.11.2017
comment
@ DavidC.Rankin, вы неправильно прочитали вопрос   -  person M.M    schedule 26.11.2017
comment
@ M.M - добавь еще одну в мой список неправильно прочитанных - уж точно не первый и, наверное, не последний ...   -  person David C. Rankin    schedule 26.11.2017
comment
@AnttiHaapala Как вы добавили 3 дублирующих ссылки?   -  person iBug    schedule 26.11.2017
comment
Владельцы @iBug Mjölnir могут добавить до 5 дублирующих ссылок с простой функцией редактирования.   -  person Antti Haapala    schedule 26.11.2017


Ответы (2)


Когда вы запускаете программу, символы, которые вы видите, не принадлежат вашей программе. Это echo консоли (или терминала) функция, которая показывает любой набранный вами символ (и вы даже можете стереть их до того, как нажмете Enter). Ваша программа выводит только символы с кодом ASCII 0 или 1, оба из которых невидимы.

Если вы измените putchar(c) на printf("%d", c), вы сможете увидеть последовательность 1s. Никакого нуля не будет, потому что, когда c станет нулем, цикл остановится и он не будет напечатан.

Символы '0' и '1' имеют коды ASCII 48 и 49 соответственно, несмотря на то, что ваш терминал может использовать другую кодировку. Если вы хотите вывести буквальное число 0, используйте символьную запись. Вы также можете попробовать putchar(48), но не используйте это слишком часто (позже вы обнаружите, что настоятельно не рекомендуется использовать магические числа в вашей программе).

putchar('0');
        ^ ^

Утверждение, что

c = getchar() != EOF;

эквивалентно

c = (getchar() != EOF);

происходит из-за приоритета оператора. Оператор != (неравенство) имеет более высокий приоритет над = (присвоение значения), поэтому он оценивается до присвоения.

Наконец, это крайне редко кто-то написал. Правильное намерение - написать это:

while ( (c = getchar()) != EOF )
person iBug    schedule 26.11.2017
comment
Отличное объяснение, и я узнал кое-что о функции эха, чего раньше не знал, спасибо! - person H3G3moKnight; 26.11.2017
comment
@ H3G3moKnight Я добавил ссылку для echo. - person iBug; 26.11.2017
comment
Я не согласен с Despite not being always, character.... ASCII всегда является ASCII, даже если ОС / Терминал использует другую кодовую страницу, первые 7 битов ASCII дают одинаковые значения. Однако кодировки действительно могут отличаться. - person Matan Shahar; 26.11.2017
comment
@MatanShahar Изменен. - person iBug; 26.11.2017

Дело в том, что c = (getchar() != EOF) он получает один входной символ, а затем сравнивает. Если это не EOF, результатом будет 1. Потом назначается. Значение оператора присваивания - это присваиваемое значение. Он входит в петлю. Печатает символ со значением ascii 1. Но этот символ не печатается, поэтому вы ничего не видите.

Как только он получит EOF, он выйдет из цикла. Таким образом, вы никогда не увидите ничего, кроме символа со значением ascii _5 _ (даже если вы этого не видите, так как он не печатается). Они известны как символы ascii-control. (Не относится к классу для печати).

Также вы сказали, что как c=0 или c=1 он должен печатать 0 или 1. Тогда попробуйте этот простой код

int c= 68;
putchar(c);

Проверьте вывод, и вы поймете, что происходит, когда мы пытаемся напечатать. Печатается символ, ascii-код которого 68, а не значение 68.

Правильный способ сделать это - ((c = getchar()) != EOF).

Первоначально я упоминал, что на некоторых машинах печатаются забавные символы. Представление непечатаемых символов зависит от используемой кодировки. Это может быть некоторая нестандартная кодировка (не-юникод), которая присваивает ascii-коду 1 какое-то представление. (Нарушая идею непечатаемых материалов)

person user2736738    schedule 26.11.2017
comment
Да, я только что просмотрел таблицу символов ASCII и увидел, что значения от 0 до 31 и 127 представляют собой непечатаемые управляющие символы. Это многое объяснило бы. - person H3G3moKnight; 26.11.2017
comment
По крайней мере, вы видите ASCII 10 (\n), верно? - person iBug; 26.11.2017
comment
@iBug .: Ага .... - person user2736738; 26.11.2017