Я пытаюсь скомпилировать этот фрагмент кода из книги «Язык программирования C» (K&R). Это простая версия программы UNIX wc
:
#include <stdio.h>
#define IN 1; /* inside a word */
#define OUT 0; /* outside a word */
/* count lines, words and characters in input */
main()
{
int c, nl, nw, nc, state;
state = OUT;
nl = nw = nc = 0;
while ((c = getchar()) != EOF) {
++nc;
if (c == '\n')
++nl;
if (c == ' ' || c == '\n' || c == '\t')
state = OUT;
else if (state == OUT) {
state = IN;
++nw;
}
}
printf("%d %d %d\n", nl, nw, nc);
}
И я получаю следующую ошибку:
$ gcc wc.c
wc.c: In function ‘main’:
wc.c:18: error: ‘else’ without a previous ‘if’
wc.c:18: error: expected ‘)’ before ‘;’ token
Второе издание этой книги датировано 1988 годом, и я новичок в C. Может быть, это связано с версией компилятора, а может, я просто несу чушь.
Я видел в современном коде C другое использование main
функции:
int main()
{
/* code */
return 0;
}
Это новый стандарт или я все еще могу использовать основной без типов?
|| c = '\t')
. Это похоже на другой код в этой строке?Ответы:
Ваша проблема связана с определениями препроцессора
IN
иOUT
:Обратите внимание, что у вас есть точка с запятой в конце каждого из них. Когда препроцессор расширяет их, ваш код будет выглядеть примерно так:
Эта вторая точка с запятой приводит к
else
тому, что предыдущееif
совпадение отсутствует, потому что вы не используете фигурные скобки. Итак, удалите точки с запятой из определений препроцессораIN
иOUT
.Урок, усвоенный здесь, состоит в том, что операторы препроцессора не должны заканчиваться точкой с запятой.
Кроме того, всегда следует использовать скобки!
В приведенном
else
выше коде нет неоднозначности.источник
Основная проблема с этим кодом в том, что это не код от K&R. Он включает точки с запятой после определений макросов, которых не было в книге, что, как указывали другие, изменяет значение.
За исключением случаев внесения изменений в попытке понять код, вы должны оставить его в покое, пока вы его не поймете. Вы можете безопасно изменять только тот код, который вам понятен.
Вероятно, это была просто опечатка с вашей стороны, но она иллюстрирует необходимость понимания и внимания к деталям при программировании.
источник
После макроса не должно быть точек с запятой,
и это, вероятно, должно быть
источник
;
была опечатка, которая не повлияла на проблему, что означает опечатку в вашем вопросе, а не в коде, который вы фактически использовали.Определения IN и OUT должны выглядеть так:
Проблема была в точках с запятой! Объяснение простое: и IN, и OUT являются директивами препроцессора, по сути, компилятор заменит все вхождения IN на 1 и все вхождения OUT на 0 в исходном коде.
Поскольку в исходном коде после 1 и 0 была точка с запятой, при замене IN и OUT в коде дополнительная точка с запятой после числа приводила к недопустимому коду, например, к этой строке:
В итоге получилось так:
Но вы хотели вот этого:
Решение: удалите точку с запятой после чисел в исходном определении.
источник
Как видите, возникла проблема с макросами.
У GCC есть опция остановки после предварительной обработки. (-E) Эта опция полезна, чтобы увидеть результат предварительной обработки. На самом деле этот метод важен, если вы работаете с большой базой кода на c / c ++. Обычно у make-файлов есть цель, которую нужно остановить после предварительной обработки.
Для быстрой справки: вопрос SO охватывает варианты - как мне увидеть исходный файл C / C ++ после предварительной обработки в Visual Studio? . Он начинается с vc ++, но также имеет параметры gcc, упомянутые ниже .
источник
Не совсем проблема, но декларация
main()
тоже датирована, должно быть примерно так.Компилятор примет возвращаемое значение int для функции без одного, и я уверен, что компилятор / компоновщик будет работать с отсутствием объявления для argc / argv и отсутствием возвращаемого значения, но они должны быть там.
источник
Попробуйте добавить явные скобки вокруг блоков кода. Стиль K&R может быть неоднозначным.
Посмотрите на строку 18. Компилятор сообщает вам, в чем проблема.
источник
if
позже добавите строку в свой блок, если вы забудете добавить фигурные скобки, потому что ваш блок теперь состоит из более чем одной строки, может потребоваться время для отладки этой ошибки ...if
предложение и «забывать» обновлять фигурные скобки, тогда, ну, вы не очень хороший программист.Самый простой способ - использовать скобки вроде {} для каждого
if
иelse
:источник
Как указывали другие ответы, проблема заключается в
#define
точках с запятой. Чтобы минимизировать эти проблемы, я всегда предпочитаю определять числовые константы какconst int
:Таким образом вы избавитесь от множества проблем и возможных проблем. Он ограничен всего двумя вещами:
Ваш компилятор должен поддерживать
const
- что в 1988 году в целом было неправдой, но теперь оно поддерживается всеми обычно используемыми компиляторами. (AFAIKconst
"заимствовано" из C ++.)Вы не можете использовать эти константы в некоторых особых местах, где вам понадобится строковая константа. Но я думаю, ваша программа не в этом.
источник
const int
нельзя использовать в C.