Состояние всегда верно. Ошибка в моем коде или ошибка в моей IDE? - PullRequest
0 голосов
/ 21 апреля 2019

Я выполняю некоторые упражнения из «Языка программирования Си» (второе издание), и я нахожусь на 1-23, где вам нужно разработать программу, которая убирает комментарии.

Это то, что у меня так далеко:

#include <stdio.h>

#define CODE 0
#define START_COMMENT 1
#define END_COMMENT 2
#define COMMENT 3
#define INQUOTE 4

/* this is a test */

/* this is a *** comment maybe / but still testing */

main() {
    char c;
    char state=CODE;
    while ((c = getchar()) != EOF) {

        if(state == CODE) {
            if (c == '/') {
                state = START_COMMENT; /* this works? */
            }
            else if (c == '"' || c == '\'') {
                state = INQUOTE;
                putchar(c);
            }
            else {
                putchar(c);
            }
        }
        else if(state == INQUOTE) {
            if (c == '"' || c == '\'') {
                state = CODE;
                putchar(c);
            }
            else {
                putchar(c);
            }
        }
        else if(state == START_COMMENT) {
            if (c == '*') {
                state = COMMENT;
            }
            else {
                putchar('/');
                putchar(c);
                state = CODE;
            }
        }
        else if(state == COMMENT) {
            if (c == '*') {
                state = END_COMMENT;
            }
        }
        else if(state == END_COMMENT) {
            if (c == '/') {
                state = CODE;
            }
            else
                state = COMMENT;
        }
    }
}

Я использую CLion на Mac, и он жалуется, что строка 54 всегда оценивается как "true". Что это за строчка внизу:

else if(state == END_COMMENT) {

Несмотря на это замечание, программа, похоже, работает до сих пор ...

Всегда ли эта строка имеет значение true, и если да, то почему? Потому что я не вижу в этом ничего плохого.

1 Ответ

1 голос
/ 21 апреля 2019

Как указано в комментариях, это гораздо легче отладить как оператор switch.Я преобразовал его в переключатель, и проблемы с окончательными условиями if / else исчезли.

Я также использую CLion на Mac и видел предупреждения, которые вы видели.

Несмотря на вышеприведенные комментарии, ваш код обрабатывает стиль c '/ * .... * / commentsправильно.

Я думаю, что полезно сообщить людям, что это препроцессор, который просто удаляет комментарии c старого стиля /*..*/, а не //... из кода, а затем выдает раздетый код.

Конечный автомат НАМНОГО проще читать как оператор switch, а также легче отлаживать.

Обратите внимание, что в одном месте вы проверяли один из двух символов, что позволило использовать стиль перехода в одном изоператоры switch.

Иногда, когда легче написать код более «просто», чем выяснить, почему компилятор считает, что условие всегда будет выполнено, лучше всего следовать рекомендациям и упрощать.Надеюсь, что это нормально для ваших целей.

Пожалуйста, дайте мне знать, если у вас есть какие-либо вопросы.

#include <stdio.h>

const char CODE = 0;
const char START_COMMENT = 1;
const char END_COMMENT = 2;
const char COMMENT = 3;
const char INQUOTE = 4;

// Preprocessor which discards comments
int main() {
    int c;
    char state = CODE;
    while (EOF != (c = getchar())) {

        switch (state) {
            case CODE:

                switch (c) {
                    case '/':  // If we are in a comment, we will strip this section of the code
                        // check if this is the start of a comment:
                        state = POTENTIAL_COMMENT;
                        break;
                    case '"':
                    case '\'':
                        state = INQUOTE;
                        putchar(c);
                        break;
                    default:
                        putchar(c);
                }
                break;
            case INQUOTE:
                if (c == '"' || c == '\'') {
                    state = CODE;
                }
                putchar(c);
                break;
            case POTENTIAL_COMMENT:
                switch (c) {
                    case '*':   // We saw the '/', so now we se the '*' and we are in a comment, just eat the char
                        state = COMMENT;
                        break;
                    case '/':
                        state = LINE_COMMENT;
                        break;
                    default:
                        putchar('/');  // we saw a '/' before, but it wasn't really the start of a comment, so put the '/' back and the current char
                        putchar(c);
                        state = CODE;
                }
            case COMMENT:
                if (c == '*') {
                    state = END_COMMENT;
                }
                break;
            case LINE_COMMENT:
                if (c == '\n')
                    state = CODE;
                break;
            case END_COMMENT:
                if (c == '/') {
                    state = CODE;
                } else
                    state = COMMENT;
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...