Как правильно обрабатывать эту проверку ошибок? - PullRequest
2 голосов
/ 11 июля 2011

У меня есть функция, которой нужно передать строку с двумя числами (в виде регулярного выражения: /-?[0-9]+ -?[0-9]+/) и вернуть второе.

Я решил, что программа должна выполнить проверку ошибок. Во-первых, он должен проверить, действительно ли строка имеет желаемую форму; во-вторых, он должен гарантировать, что первые числа (те, которые не возвращены) являются последовательными.

Я давно программирую, и это не сложная задача. (Это немного усложняется из-за того, что числа не должны вписываться в машинное слово.) Но мой вопрос о том, как я должен сделать это, а не о том, как я может . Все решения, которые я придумала, несколько уродливы.

  • Я мог бы использовать глобальную переменную, чтобы сохранить значения и сравнить их (или просто оставить значение там, если оно NULL); это похоже на неправильную вещь.
  • Я мог бы передать одно или оба возвращаемого значения и первого / последнего номера последней / текущей строки по ссылке и изменить их
  • Я мог бы использовать возвращаемое значение, чтобы получить логическое значение, потому что была / не была ошибка

Так что любые мысли, касающиеся правильного способа справиться с проверкой ошибок такого рода в Си, приветствуются.


Это связано с гораздо более теоретическим вопросом, который я задавал по теории . Для справки, вот функция:

char*
scanInput(char* line)
{
    int start = 0;
    while (line[start] == ' ' || line[start] == '\t')
        start++;
    if (line[start] == '#')
        return NULL;    // Comment
    if (line[start] == '-')
        start++;
    while (line[start] >= '0' && line[start] <= '9')
        start++;
    while (line[start] == ' ' || line[start] == '\t')
        start++;
    int end = start;
    if (line[end] == '-')
        end++;
    while (line[end] >= '0' && line[end] <= '9')
        end++;
    if (start == end)
        return NULL;    // Blank line, or no numbers found
    line[end] = '\0';

    return line + start;
}

и это называется так:

while(fgets(line, MAX_LINELEN, f) != NULL) {
    if (strlen(line) > MAX_LINELEN - 5)
        throw_error(talker, "Maximum line length exceeded; file probably not valid");
    char* kept = scanInput(line);
    if (kept == NULL)
        continue;
    BIGNUM value = strtobignum(kept);
    if (++i > MAX_VECLEN) {
        warning("only %d terms used; file has unread terms", MAX_VECLEN);
        break;
    }
    // values are used here
}

Ответы [ 2 ]

2 голосов
/ 11 июля 2011

Традиционное решение в C состоит в том, чтобы использовать передачу по ссылке (указатели) для возврата значений, которые вычисляет ваша функция, и использовать возвращаемое значение для обработки ошибок, так же, как это делает scanf.

int scanInput(char **line_p int *number){
    char * line = *line_p;
    ...
    if(something bad happens){
        return 1;
    }
    ...
    *linep = line + start;
    *number = ...;
    return 0; //success
}

int main(){
    char word[100]; strcpy(word, "10 17");
    char *line = word;
    int number;
    switch(scanInput(&line, &number)){
        case 1:
        default:
    }
}

Дополнительные очки:

  • Возможно, было бы неплохо использовать некоторое перечисление, чтобы придать смысл кодам ошибок.
  • Если вы можете использовать C ++ (или аналогичные), исключения часто являются лучшим решением для обработки ошибок, так как вам больше не нужно заполнять свой код ifs
  • Глобальные переменные являются в целом злом. Если вы склонны использовать их, рассмотрите возможность инкапсуляции нужного вам состояния в структуру и передачи указателя на него. Обрабатывайте его как указатель «this» в ОО-смысле.
1 голос
/ 11 июля 2011

В конечном итоге вам нужно выделить и преобразовать оба больших числа в каждой строке.Чтобы убедиться, что первое число в строке соответствует предыдущему, вам нужно будет сохранить последний найденный номер.Итак, вам, вероятно, понадобится такая структура:

BIGNUM old_value = 0;  // See notes below

while (fgets(line, sizeof(line), f) != 0)
{
    BIGNUM value1;
    BIGNUM value2;
    if (ScanDoubleBigNum(line, &value1, &value2) != 0)
        ...handle line format error...
    if (old_value == 0 || are_consecutive(old_value, value1))
    {
        // OK - valid information found
        // Release old_value
        old_value = value1;
        process(value2);
        // Release value2
    }
    else
        ...handle non-consecutive error...
}

Функция are_consecutive() определяет, будет ли ее второй аргумент на один больше первого.Функция process() делает все, что вам нужно, со вторым значением.Функция ScanDoubleBigNum() связана с вашим ScanInput(), но она читает два значения.Фактический код вызовет другую функцию (назовите ее ScanBigNum()), содержащую примерно половину ScanInput() (поскольку она содержит по существу один и тот же код дважды), плюс преобразование, которое в настоящее время происходит в вашем цикле.Код в ScanDoubleBigNum() вызовет ScanBigNum() дважды.Обратите внимание, что ScanBigNum() нужно будет определить, где заканчивается сканирование, чтобы второй вызов мог продолжиться там, где остановился первый.

Я позволю себе предположить, что BIGNUM - это распределенная структура, определяемаяуказатель, поэтому инициализация BIGNUM old_value = 0; - это способ указать, что значения пока нет.Предположительно есть функция для освобождения BIGNUM.Если это неверно, то вам нужно адаптировать предложенный код для соответствия фактическому поведению типа BIGNUM.(Это основано на OpenSSL или коде SSLeay?)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...