[c] 이 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의 코드 가 아니라는 것입니다 . 이 책에는없는 매크로 정의 뒤에 세미콜론이 포함되어 있으며 다른 사람들이 지적했듯이 의미를 변경합니다.

코드를 이해하기 위해 변경하는 경우를 제외하고는 코드를 이해할 때까지 그대로 두어야합니다. 이해하는 코드 만 안전하게 수정할 수 있습니다.

이것은 아마도 여러분의 오타 일 뿐이지 만 프로그래밍 할 때 세부 사항에 대한 이해와주의의 필요성을 보여줍니다.


답변

매크로 뒤에는 세미콜론이 없어야합니다.

#define IN   1     /* inside a word */
#define OUT  0     /* outside a word */

그리고 아마

if (c == ' ' || c == '\n' || c == '\t')


답변

IN과 OUT의 정의는 다음과 같아야합니다.

#define IN   1     /* inside a word  */
#define OUT  0     /* outside a word */

세미콜론이 문제를 일으켰습니다! 설명은 간단합니다. IN과 OUT은 모두 전 처리기 지시문입니다. 본질적으로 컴파일러는 소스 코드에서 IN의 모든 발생을 1로, OUT의 모든 발생을 0으로 대체합니다.

원래 코드에는 1과 0 뒤에 세미콜론이 있었기 때문에 코드에서 IN과 OUT이 바뀌었을 때 숫자 뒤의 추가 세미콜론이 잘못된 코드를 생성했습니다. 예를 들면 다음과 같습니다.

else if (state == OUT)

다음과 같이 보입니다.

else if (state == 0;)

그러나 당신이 원했던 것은 다음과 같습니다.

else if (state == 0)

해결 방법 : 원래 정의에서 숫자 뒤의 세미콜론을 제거하십시오.


답변

보시다시피 매크로에 문제가 있습니다.

GCC에는 전처리 후 중지하는 옵션이 있습니다 .(-E)이 옵션은 전처리 결과를 보는 데 유용합니다. 사실이 기술은 c / c ++에서 대규모 코드 기반으로 작업하는 경우 중요한 기술입니다. 일반적으로 메이크 파일에는 전처리 후 중지 할 대상이 있습니다.

빠른 참조 : SO 질문은 옵션을 다룹니다. Visual Studio에서 전처리 한 후 C / C ++ 소스 파일을 어떻게 볼 수 있나요? . vc ++로 시작하지만 아래에 언급 된 gcc 옵션있습니다 .


답변

정확히 문제는 아니지만의 선언 main()도 날짜가 적혀 있습니다.

int main(int argc, char** argv) {
    ...
    return 0;
}

컴파일러는 함수가없는 함수에 대해 int 반환 값을 가정하고 컴파일러 / 링커가 argc / argv에 대한 선언 부족과 반환 값 부족을 해결할 것이라고 확신하지만 거기에 있어야합니다.


답변

코드 블록 주위에 명시적인 중괄호를 추가해보십시오. K & R 스타일은 모호 할 수 있습니다.

18 행을보십시오. 컴파일러는 문제가있는 곳을 알려줍니다.

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