Что такое функция «утверждать»?

198

Я изучал учебники OpenCV и наткнулся на функцию assert; что он делает?

  • 18
    Обратите внимание на примечание от man assert: «assert () реализован как макрос; если у протестированного выражения есть побочные эффекты, поведение программы будет отличаться в зависимости от того, определен ли NDEBUG. Это может создавать гейзенговские ошибки, которые исчезают при включении отладки. «.
  • 1
    opengroup.org/onlinepubs/000095399/functions/assert.html
Показать ещё 3 комментария
Теги:
assert

9 ответов

208
Лучший ответ

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

Например:

assert(length >= 0);  // die if length is negative.

Вы также можете добавить более информативное сообщение, которое будет отображаться, если оно не так:

assert(length >= 0 && "Whoops, length can't possibly be negative! (didn't we just check 10 lines ago?) Tell jsmith");

Или иначе:

assert(("Length can't possibly be negative! Tell jsmith", length >= 0));

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

// BAD
assert(x++);

// GOOD
assert(x);    
x++;

// Watch out! Depends on the function:
assert(foo());

// Here a safer way:
int ret = foo();
assert(ret);

Из комбинации вызова программы abort() и не гарантируется что-либо сделать, утверждения должны использоваться только для проверки того, что разработчик предположил, а не, например, пользователя, вводящего число, а не буквы ( которые должны обрабатываться другими средствами).

  • 44
    « assert обычно вызывает исключение» - в C ++ оно не вызывает «исключение», которое вызывает abort ... оно немного отличается.
  • 5
    Я не думаю, что этот ответ относится к тем же языкам, на которых вопрос помечен (C и C ++). В C и C ++ assert не вызывает исключение, у него есть круглые скобки вокруг аргумента, а символ # не вводит комментарий.
Показать ещё 4 комментария
95

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

  • 114
    Ну, не совсем. «Убедитесь, что свет выключен» означает «проверьте свет и выключите его, если он включен», а не «посмотрите, выключен ли свет и, если нет, пожалуйста, взорвитесь». Я бы сказал, что «двойная проверка» - это более близкий перевод ,
  • 7
    @Luke, который иллюстрирует чудеса английского языка, потому что язык предлагает много способов сказать то же самое. Но рассмотрим утверждение (длина> 0). Таким образом, мы можем перевести это как «перепроверить длину больше нуля» или «убедиться, что длина больше нуля» . Хотя явно оба варианта работают, я все же предпочитаю свой;)
Показать ещё 2 комментария
11

Взгляните на

Пример программы assert() в С++

Многие компиляторы предлагают assert() макро. Макрос assert() возвращает TRUE если его параметр оценивает TRUE и принимает какое-то действие, если оно оценивает FALSE. Многие компиляторы будут прервать программу на assert(), который терпит неудачу; другие будут генерировать исключение

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

Например,

#include <stdio.h>
#include <assert.h>

void analyze (char *, int);

int main(void)
{
   char *string = "ABC";
   int length = 3;

   analyze(string, length);
   printf("The string %s is not null or empty, "
          "and has length %d \n", string, length);
}

void analyze(char *string, int length)
{
   assert(string != NULL);     /* cannot be NULL */
   assert(*string != '\0');    /* cannot be empty */
   assert(length > 0);         /* must be positive */
}

/****************  Output should be similar to  ******************
The string ABC is not null or empty, and has length 3
  • 9
    Не должно быть "если NDEBUG определен"?
  • 3
    Не должно ли быть .... (я думал, что комментарии могут быть отредактированы ....)
Показать ещё 2 комментария
6

Функция assert() может диагностировать ошибки программы. Он определен в ASSERT.H, а его прототип

void assert (int expression); Выражение аргумента может быть любым, что вы хотите проверить - переменной или любым выражением C. Если выражение принимает значение TRUE, assert() ничего не делает. Если выражение принимает значение FALSE, assert() выводит сообщение об ошибке на stderr и прерывает выполнение программы.

Как вы используете assert()?. Он чаще всего используется для отслеживания ошибок программы (которые отличаются от ошибок компиляции). Ошибка не препятствует компиляции программы, но она заставляет ее давать неправильные результаты или запускаться неправильно (например, блокирование). Например, программа финансового анализа, которую вы пишете, может иногда давать неверные ответы. Вы подозреваете, что проблема вызвана переменной interest_rate, принимающей отрицательное значение, чего никогда не должно было случиться. Чтобы проверить это, поместите оператор

assert (interest_rate >= 0); в местах в программе, где используется процент_трассы. Если переменная когда-либо становится отрицательной, макрос assert() предупреждает вас. Затем вы можете изучить соответствующий код, чтобы найти причину проблемы.

Чтобы узнать, как работает assert(), запустите пример программы ниже. Если вы вводите ненулевое значение, программа отображает значение и обычно заканчивается. Если вы вводите нуль, макрос assert() выдает ненормальное завершение программы. Точное сообщение об ошибке, которое вы видите, будет зависеть от вашего компилятора, но здесь типичный пример:

Утверждение не выполнено: x, файл list19_3.c, строка 13 Обратите внимание, что для того, чтобы assert() работал, ваша программа должна быть скомпилирована в режиме отладки. Информацию о включении режима отладки см. В документации вашего компилятора (как это объясняется в одно мгновение). Когда вы позже компилируете окончательную версию в режиме выпуска, макросы assert() отключены.

 int x;

 printf("\nEnter an integer value: ");
 scanf("%d", &x);

 assert(x >= 0);

 printf("You entered %d.\n", x);
 return(0);

Введите целочисленное значение: 10

Вы ввели 10.

Введите целочисленное значение: -1

Сообщение об ошибке: Аномальное завершение программы

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

  • 0
    Вы объяснили, как ваша программа-пример работает с assert. Не так, как само утверждение работает. Как это ненормально завершает программу? это бросает какое-то исключение? Какие? Это создает специальный сигнал? какой сигнал? Могут ли утверждения быть "перехвачены" каким-либо механизмом C ++ try-catch?
3

В большинстве компиляторов, например, для "составления исключений" и "прекращения выполнения", это может быть правдой, но не для всех. (BTW, существуют ли утверждения, которые действительно вызывают исключения?)

Здесь интересное, немного другое значение assert, используемое c6x и другими компиляторами TI: при просмотре определенных утверждений assert эти компиляторы используют информацию в этом выражении для выполнения определенных оптимизаций. Злая.

Пример в C:

int dot_product(short *x, short *y, short z)
{
  int sum = 0
  int i;

  assert( ( (int)(x) & 0x3 ) == 0 );
  assert( ( (int)(y) & 0x3 ) == 0 );

  for( i = 0 ; i < z ; ++i )
    sum += x[ i ] * y[ i ];
  return sum;
}

Это говорит компилятору, что массивы выровнены по 32-битным границам, поэтому компилятор может генерировать конкретные инструкции для такого выравнивания.

  • 1
    Так что же они делают, если assert ложен, а NDEBUG не установлен? Если это версия assert из <assert.h>, то стандарт требует, чтобы он распечатал сообщение и прервал его. Очевидно, что в стандарте не говорится, что им не разрешено оптимизировать, основываясь на правдивости утверждения, но чтобы соответствовать требованиям, им все равно придется прервать работу, если она ложная.
  • 1
    они следуют стандартному поведению
1

Assert позволяет остановить выполнение, если условие (утверждение) ложно.

Например (псевдокод):

Bank myBank = Bank.GetMyStuff();

assert(myBank != NULL);

// .. Continue.

Если myBank равен NULL, функция прекратит выполнение и возникнет ошибка. Это очень хорошо для того, чтобы сделать код многократного использования приемлемыми условиями и т.д.

  • 2
    Вы хотите подтвердить (myBank! = NULL), если хотите остановить, когда myBank равен NULL.
  • 0
    assert вызовет abort() не просто вернется из функции.
0

С++ 11 Стандартная черновая версия N3337

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf

19.3 Утверждения

1 Заголовок <cassert> , описанный в (Таблица 42), предоставляет макрос для документирования утверждений программы на С++ и механизм отключения проверки подтверждения.

2 Содержимое совпадает с заголовком библиотеки Standard C < assert.h > .

C99 N1256 стандартная черта

http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf

7.2 Диагностика < assert.h >

1 Заголовок <assert.h> определяет макрос assert и ссылается на другой макрос NDEBUG, который не определен <assert.h>. Если NDEBUG определяется как имя макроса на в исходном файле, где включен < assert.h > , макрос assert определяется просто как

 #define assert(ignore) ((void)0)

Макрос утверждения переопределяется в соответствии с текущим состоянием NDEBUG каждый раз, когда <assert.h>.

2. Макрос утверждения должен быть реализован как макрос, а не как фактическая функция. Если определение макроса подавляется для доступа к фактической функции, поведение undefined.

7.2.1 Диагностика программы

7.2.1.1 Утверждающий макрос

Сводка

1.

#include <assert.h>
void assert(scalar expression);

Описание

2 Макрос утверждений ставит диагностические тесты в программы; он расширяется до выражения void. Когда он выполняется, если выражение (которое должно иметь скалярный тип) является ложным (то есть, сравнивается с 0), макрос assert записывает информацию о конкретном вызове, который (включая текст аргумента, имя исходного файла, исходную строку номер и имя прилагаемой функции - последние являются соответственно значениями макросы предварительной обработки __FILE__ и __LINE__ и идентификатора __func__) в стандартном потоке ошибок в формате, определяемом реализацией. 165) Это затем вызывает функцию прерывания.

Возвращает

3 Макрос assert не возвращает значение.

0

Это функция, которая остановит выполнение программы, если значение, которое оно оценило, является ложным. Обычно он окружен макросом, так что он не компилируется в результирующий двоичный файл при компиляции с настройками выпуска.

Он предназначен для тестирования допущений, которые вы сделали. Например:

void strcpy(char* dest, char* src){
    //pointers shouldn't be null
    assert(dest!=null);
    assert(src!=null);

    //copy string
    while(*dest++ = *src++);
}

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

  • 0
    почему мы просто не используем if & else и не добавляем информацию для регистрации?
  • 1
    Потому что вы никогда не должны передавать пустой указатель на strcpy. Это одна из тех вещей, которые не должны происходить. Если нулевой указатель был передан, это означает, что что-то на более высоком уровне испортилось. В лучшем случае вам в конечном итоге приходится отказывать программе дальше от проблемы из-за неожиданных значений данных (либо dest неверно, либо null).
-3

Кроме того, вы можете использовать его для проверки успешного выполнения динамического размещения.

Пример кода:

int ** p;
p = new int * [5];      // Dynamic array (size 5) of pointers to int
for (int i = 0; i < 5; ++i) {
    p[i] = new int[3]; // Each i(ptr) is now pointing to a dynamic
                       // array (size 3) of actual int values
}

assert (p);            // Check the dynamic allocation.

Аналогично:

if (p == NULL) {
    cout << "dynamic allocation failed" << endl;
    exit(1);
}
  • 3
    Номер new генерирует исключение при сбое выделения , если не указано nothrow (который вы не здесь). Кроме того, ваше форматирование странно, а exit - зло.
  • 0
    Да ты прав. Я забыл добавить не. Хотелось бы увидеть, как вы будете использовать вместо выхода
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню