Как использовать C assert, чтобы сделать код более безопасным? - PullRequest
4 голосов
/ 26 декабря 2009

Чтение разн. учебные пособия, связанные с разработкой SDL Я нашел два разных примера, выполняющих одно и то же, но по-разному. Мне было интересно, какой из этих двух вариантов вы считаете верным, если судить с точки зрения «безопасности» и удобства сопровождения кода.

В первом примере программист вообще не использует assert, но код выглядит нормально (по крайней мере, на мой взгляд):

int main(){
        SDL_Surface *screen;

        /** Initialize SDL */
        if(SDL_Init(SDL_INIT_VIDEO)!=0){
                fprintf(stderr,"Unable to initialize SDL: %s",SDL_GetError());
        }
        atexit(SDL_Quit);

        /** Sets video mode */
        screen=SDL_SetVideoMode(640,480,16,SDL_HWSURFACE);
        if(screen==NULL){
                fprintf(stderr,"Unable to set video mode: %s",SDL_GetError());
        }

        return (0);
}

Во втором примере программист [другой] использует другой подход, что-то вроде (код не совсем копирование-вставка):

int main(){
        SDL_Surface* screen;

        /** Initialize SDL */
        assert(SDL_Init(SDL_INIT_VIDEO)==0);
        atexit(SDL_Quit);

        /** Sets video mode */
        screen=SDL_SetVideoMode(640,480,16,SDL_HWSURFACE);
        assert(screen!=NULL);

        return (0);
}

Можно ли "заменить" условия if (из первого примера) утверждениями, как во втором примере?

Какова правильная стратегия (если есть)?

Ответы [ 4 ]

24 голосов
/ 26 декабря 2009

Это не нормально делать эту замену. Второй пример - неправильно , потому что assert(x) расширяется до ничего в неотладочных сборках (когда определено NDEBUG). Это означает, что проверки указателя в assert выше удалены из кода в сборках выпуска. Это определенно неправильно.

Итак, когда следует использовать assert? Это полезно для документирования и отладки . В некотором смысле, вы говорите: «Я уверен, что это условие выполняется, и помещаю его здесь как assert, чтобы перехватывать плохой код во время отладки и документировать условие для читателей кода».

Итак, между этими двумя примерами есть БОЛЬШАЯ разница. Для таких вещей, как проверка возвращаемого значения malloc, assert является неправильным, потому что нет гарантии, что они вернут не-NULL, и, как я уже упоминал выше, assert(x) означает «Я полностью уверен» x это правда ", а не просто" Если x не правда, это плохо ". Для этого используется if(x) good(); else bad(); control.

SDL_Init и SDL_SetVideoMode могут вернуть -1 и NULL соответственно.

4 голосов
/ 26 декабря 2009

assert следует использовать, когда дела идут не так, как надо, неожиданным образом. Обычно, если утверждение не выполняется, это означает, что в программе есть ошибка. Утверждения не используются для ожидаемых ошибок, которые могут произойти (то есть не удалось открыть файл, не удалось что-то инициализировать и т. Д.).

В приведенном вами примере assert не кажется самым логичным решением. Когда программе не удалось инициализировать SDL, имеет больше смысла сообщить об этом пользователю в структурированном виде, чем выдать утверждение (которое может просто вызвать ошибку сегмента в некоторых системах).

3 голосов
/ 26 декабря 2009

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

assert( condition );
if ( !condition )
    handle error;
1 голос
/ 26 декабря 2009

Я использую утверждение для документирования предусловий и постусловий. (определение намерения функции)

как ..

double positive_division(double dividend, double divisor)
{
    //preconditions
    ASSERT(dividend>=0);
    ASSERT(divisor >0);

    double quotient = dividend/divisor;

    //postconditions    
    ASSERT(quotient>=0);
    return quotient;
}
...