이 1988 C 코드의 문제점은 무엇입니까?
저는 "The C Programming Language"(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;
}
이것은 새로운 표준입니까 아니면 유형없는 메인을 사용할 수 있습니까?
문제는 당신의 처리기 정의 함께 IN
하고 OUT
:
#define IN 1; /* inside a word */
#define OUT 0; /* outside a word */
이들 각각에 후행 세미콜론이 어떻게 있는지 주목하십시오. 전처리 기가 확장하면 코드는 대략 다음과 같습니다.
if (c == ' ' || c == '\n' || c == '\t')
state = 0;; /* <--PROBLEM #1 */
else if (state == 0;) { /* <--PROBLEM #2 */
state = 1;;
두 번째 세미콜론은 중괄호를 사용하지 않기 때문에 else
이전 if
에 일치하는 항목이 없도록합니다. 따라서 IN
및 의 전 처리기 정의에서 세미콜론을 제거하십시오 OUT
.
여기서 배운 교훈은 전 처리기 문이 세미콜론으로 끝날 필요가 없다는 것입니다.
또한 항상 중괄호를 사용해야합니다!
if (c == ' ' || c == '\n' || c == '\t') {
state = OUT;
} else if (state == OUT) {
state = IN;
++nw;
}
else
위 코드에는 모호함 이 없습니다 .
이 코드의 주요 문제점 은 K & R의 코드 가 아니라는 것입니다 . 다른 사람들이 지적했듯이 의미를 변경하는 책에는없는 매크로 정의 뒤에 세미콜론이 포함됩니다.
코드를 이해하기 위해 변경하는 경우를 제외하고는 코드를 이해할 때까지 그대로 두어야합니다. 이해하는 코드 만 안전하게 수정할 수 있습니다.
This was probably just a typo on your part, but it does illustrate the need for understanding and attention to details when programming.
There should not be any semicolons after the macros,
#define IN 1 /* inside a word */
#define OUT 0 /* outside a word */
and it should probably be
if (c == ' ' || c == '\n' || c == '\t')
The definitions of IN and OUT should look like this:
#define IN 1 /* inside a word */
#define OUT 0 /* outside a word */
The semicolons were causing the problem! The explanation is simple: both IN and OUT are preprocessor directives, essentially the compiler will replace all occurrences of IN with a 1 and all occurrences of OUT with a 0 in the source code.
Since the original code had a semicolon after the 1 and the 0, when IN and OUT got replaced in the code, the extra semicolon after the number produced invalid code, for instance this line:
else if (state == OUT)
Ended up looking like this:
else if (state == 0;)
But what you wanted was this:
else if (state == 0)
Solution: remove the semicolon after the numbers in the original definition.
As you see there was a problem in macros.
GCC has option for stopping after pre-processing. (-E) This option is useful to see the result of pre-processing. In fact the technique is an important one if you are working with large code base in c/c++. Typically makefiles will have a target to stop after pre-processing.
For quick reference : The SO question covers the options -- How do I see a C/C++ source file after preprocessing in Visual Studio?. It starts with vc++, but also has gcc options mentioned down below.
Not exactly a problem, but the declaration of main()
is also dated, it should be like something this.
int main(int argc, char** argv) {
...
return 0;
}
The compiler will assume an int return value for a function w/o one, and I'm sure the compiler/linker will work around the lack of declaration for argc/argv and the lack of return value, but they should be there.
Try adding explicit braces around code blocks. The K&R style can be ambiguous.
Look at line 18. The compiler is telling you where the issue is.
if (c == '\n') {
++nl;
}
if (c == ' ' || c == '\n' || c == '\t') { // You're missing an "=" here; should be "=="
state = OUT;
}
else if (state == OUT) {
state = IN;
++nw;
}
A simple way is to use brackets like {} for each if
and else
:
if (c == '\n'){
++nl;
}
if (c == ' ' || c == '\n' || c == '\t')
{
state = OUT;
}
else if (state == OUT) {
state = IN;
++nw;
}
As other answers pointed out, the problem is in #define
and semicolons. To minimize these problems I always prefer defining number constants as a const int
:
const int IN = 1;
const int OUT = 0;
This way you get rid of many problems and possible problems. It is limited by just two things:
Your compiler has to support
const
- which in 1988 wasn't generally true, but now it's supported by all commonly used compilers. (AFAIK theconst
is "borrowed" from C++.)You can't use these constants in some special places where you would need a string-like constant. But I think your program isn't that case.
참고URL : https://stackoverflow.com/questions/8640818/whats-wrong-with-this-1988-c-code
'Programming' 카테고리의 다른 글
코드 골프-파이 데이 (0) | 2020.08.25 |
---|---|
포드 설치 오류 (0) | 2020.08.25 |
Asp.NET Web API-405-이 페이지에 액세스하는 데 사용되는 HTTP 동사가 허용되지 않음-처리기 매핑 설정 방법 (0) | 2020.08.25 |
소수점 이하 숫자를 얻는 방법? (0) | 2020.08.25 |
Red Hat Linux에서 표준 도구를 사용하여 파일의 행을 무작위 화하려면 어떻게해야합니까? (0) | 2020.08.25 |