Я неправильно понимаю использование assert()?

Я просматривал страницу справки assert() и застрял, когда прочитайте приведенный пример:

/* assert example */
#include <stdio.h>
#include <assert.h>

int main ()
{
  FILE * datafile;
  datafile=fopen ("file.dat","r");
  assert (datafile);

  fclose (datafile);

  return 0;
}

В этом примере assert используется для прерывания выполнения программы, если datafile сравнивается с 0, что происходит, когда предыдущий вызов fopen не увенчался успехом.

Я полностью согласен с тем, что в случае сбоя fopen() выполнение assert() прервется. Однако меня беспокоит правильность этого примера:

По моему мнению, assert() предназначено для обнаружения случаев, которые обычно не могут произойти (например, передача указателя NULL функции, в документации которой указано, что это запрещено).

В этом примере сбой при открытии файла не является чем-то обычно невозможным. На самом деле, я вижу десятки причин, по которым это не получится. Файл не может существовать, программа может работать без необходимых прав и т.д.

Я бы предпочел сделать что-то вроде:

/* not longer an assert example */
#include <stdio.h>
#include <assert.h>

int main ()
{
  FILE * datafile;
  datafile=fopen ("file.dat","r");

  if (datafile != NULL)
  {
    // Do something, whatever.
    fclose (datafile);
  } else
  {
    // Report the error somehow.
  }

  return 0;
}

Правильно ли я понимаю, как следует использовать assert()?


РЕДАКТИРОВАТЬ И ХОРОШИЕ НОВОСТИ!

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

Привет, Жюльен, я должен согласиться, код примера был выбран плохо. Сейчас его просто переписали на что-то более подходящее.

Большое спасибо, что указали на это, и приносим извинения за любые неудобства, которые это могло вам причинить.

С наилучшими пожеланиями,

И обновленный пример:

/* assert example */
#include <stdio.h>
#include <assert.h>

void print_number(int* myInt) {
  assert (myInt!=NULL);
  printf ("%d\n",*myInt);
}

int main ()
{
  int a=10;
  int * b = NULL;
  int * c = NULL;

  b=&a;

  print_number (b);
  print_number (c);

  return 0;
}

Рад видеть, что некоторые люди хорошо делают свою работу в Интернете! ;)


person ereOn    schedule 23.07.2010    source источник
comment
+1 За то, что признал, что это плохой пример. +2 За то почтовые контакты сайта.   -  person Robben_Ford_Fan_boy    schedule 23.07.2010
comment
Ваше понимание на высоте. assert предназначен для ошибок программирования, а не ошибок пользователя.   -  person GManNickG    schedule 23.07.2010
comment
Я удалил тег C++, так как в посте нет ни кусочка кода C++.   -  person Puppy    schedule 23.07.2010
comment
Парню, который проголосовал за вопрос: почему? @DeadMG: assert() можно использовать и в C++. Тег был здесь только для того, чтобы расширить аудиторию, поскольку люди, которые делают только C++, также могут быть заинтересованы в ответах.   -  person ereOn    schedule 23.07.2010
comment
@ereOn: Тогда почему бы вам не показать пример использования C ++?   -  person Puppy    schedule 23.07.2010
comment
@DeadMG: Потому что, наверное, никому, кроме тебя, нет до этого дела. Почему это так важно? Цель этого вопроса - понять использование assert(). Является ли это кодом C или C++, совершенно не имеет значения. Если вас это так сильно беспокоит, замените строковые литералы на std::string... но тогда вы, вероятно, будете жаловаться на тег C. Не хочешь?   -  person ereOn    schedule 23.07.2010
comment
В целом языковые теги предназначены для вопросов, конкретных для этого языка (большинство языков имеют assert функциональные возможности, вам потребуются сотни тегов, чтобы пометить их все), но я м тут запутался. Судя по истории редактирования, даже в первой версии вопроса была 1. ссылка на cplusplus.com и 2. примеры кода, написанные на C++. Я не понимаю, почему использование тега c++ неправильно. Также +1 отсюда   -  person jalf    schedule 23.07.2010
comment
В то время как такое использование было бы злом в реальном коде, использование assert() для создания короткого и целенаправленного примера кода имеет давнюю традицию. Код примера, правильно обрабатывающий все пути ошибок, сбивает с толку.   -  person Georg Fritzsche    schedule 23.07.2010


Ответы (3)


Вы совершенно правы, сэр. Это плохое использование assert.

person Alexandre C.    schedule 23.07.2010
comment
действительно, утверждать следует только в крайнем случае, иначе как мировой коллапс - person RvdK; 23.07.2010
comment
Спасибо за ответ. Я написал на страницу контактов, чтобы сообщить им о проблеме. Интересно, обновят ли они его. - person ereOn; 23.07.2010

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

Я просто хотел добавить ужасную историю, связанную с этим вопросом, которую я видел в кодовой базе:

assert(do_something() == NO_ERR);

Некоторым людям нельзя разрешать пользоваться клавиатурой.

person vhallac    schedule 25.07.2010
comment
Истинный. Хотя это зависит от того, что делает do_something(). если do_something() действительно do_complex_validation_that_system_state_is_valid(), то это может быть разумным, если оно не имеет побочных эффектов - person jcoder; 25.07.2010

Небольшое уведомление: лучше бы вы написали..

FILE * datafile = NULL;

Кроме того, assert работает только в режиме отладки... так что ваш метод лучше.

person shader    schedule 23.07.2010
comment
Ну, это не мой код. И хотя я обычно инициализирую свои локальные переменные, здесь datafile присваивается сразу после объявления, так что это не имеет особого значения ;) Хорошая мысль о режиме отладки, я даже не подумал об этом. - person ereOn; 23.07.2010
comment
@Praveen: assert — это макрос, который что-то делает только тогда, когда NDEBUG не определен. Так обычно в режиме отладки. - person ereOn; 23.07.2010