source

1988년식 C코드에 무슨 문제가 있나요?

factcode 2022. 7. 21. 23:33
반응형

1988년식 C코드에 무슨 문제가 있나요?

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

이게 새로운 규격인가요?아니면 타입이 없는 메인도 사용할 수 있나요?

입니다.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++에서 큰 코드 베이스를 사용하는 경우 중요합니다.일반적으로 makefile에는 전처리 후 정지할 대상이 있습니다.

빠른 참조: SO 질문은 옵션에 대해 설명합니다.Visual Studio에서 전처리 후 C/C++ 소스 파일을 표시하는 방법VC++로 시작하지만 아래 gcc 옵션도 있습니다.

정확히는 문제가 되지 않지만, 선언은main()날짜도 똑같아요. 이런 느낌일 거예요.

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

컴파일러는 int return value with o one을 가정하고 컴파일러/링커는 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;
    }

간단한 방법은 각각 {}와 같은 괄호를 사용하는 것입니다.if그리고.else:

if (c == '\n'){
    ++nl;
}
if (c == ' ' || c == '\n' || c == '\t')
{
    state = OUT;
}
else if (state == OUT) {
    state = IN;
    ++nw;
}

다른 답변에서 지적되었듯이 문제는#define및 세미콜론.이러한 문제를 최소화하기 위해 나는 항상 숫자 상수를 정의하기를 선호한다.const int:

const int IN = 1;
const int OUT = 0;

이렇게 하면 많은 문제들과 가능성 있는 문제들을 없앨 수 있다.제한은 다음 두 가지뿐입니다.

  1. 컴파일러가 다음을 지원해야 합니다.const1988년에는 일반적으로 사실이 아니었지만 지금은 일반적으로 사용되는 모든 컴파일러에서 지원됩니다.(AFAIK theconstC++에서 '빌렸다'는 것입니다).

  2. 문자열과 같은 상수가 필요한 일부 특수한 장소에서는 이러한 상수를 사용할 수 없습니다.하지만 당신의 프로그램은 그렇지 않다고 생각해요.

언급URL : https://stackoverflow.com/questions/8640818/whats-wrong-with-this-1988-c-code

반응형