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


262

Я изучал руководства по OpenCV и наткнулся на эту assertфункцию; Что это делает?


20
Обратите внимание на примечание от man assert: «assert () реализован как макрос; если у протестированного выражения есть побочные эффекты, поведение программы будет отличаться в зависимости от того, определен ли NDEBUG. Это может создать гейзенговские ошибки, которые исчезают, когда включена отладка «.
Йоханнес Шауб -


35
@ S.Lott теперь люди, которые ищут в Google, найдут эту страницу одним из лучших результатов поиска, предоставляя хороший рецензированный ответ на свой вопрос и одновременно продвигая переполнение стека, так что это +1 от меня!
Мэтт Грум

6
Это -1 от меня. Лучшим результатом поиска должна быть документация , к которой ОП должен был обратиться в первую очередь.
Гонки легкости на орбите

9
@LightnessRacesinOrbit. Называйте меня ленивым, но я предпочитаю использовать превосходные сжатые, обобщенные и объясненные чтения документации, которую предоставляют такие опытные пользователи SO, как вы. Мое сердечное спасибо :)
Тайсон Хилмер

Ответы:


298

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's a safer way:
int ret = foo();
assert(ret);

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


49
« assertобычно вызывает исключение» - в C ++ оно не вызывает «исключение», которое вызывает abort ... оно немного отличается.
Артём

5
Я не думаю, что этот ответ относится к тем же языкам, на которых задан вопрос (C и C ++). В C и C ++ assert не вызывает исключение, оно имеет круглые скобки вокруг своего аргумента, а #символ не вводит комментарий.
Стив Джессоп

Вот ваши варианты: Сделайте ответ на вики-сообществе и отредактируйте свой вопрос, удалив старый материал, попросив других разместить правильную информацию. Таким образом, отрицательные отзывы не повлияют на вашу репутацию, и люди могут улучшить ответ.
Йоханнес Шауб -

2
длина> = 0 также станет ложной, если длина равна NaN
Andreas

1
В настоящее время в VS 2015 утверждение с сообщением об ошибке не будет работать, поскольку оно вышло из строя. Это должно бытьassert("error message", expression)
Dooskington

102

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


131
Ну, не совсем. «Убедитесь, что свет выключен» означает «проверьте свет и выключите его, если он включен», а не «посмотрите, выключен ли свет и, если нет, пожалуйста, взорвитесь». Я бы сказал, что «двойная проверка» - это более близкий перевод.
Люк Маурер

7
@Luke, который иллюстрирует чудеса английского языка, потому что язык предлагает много способов сказать то же самое. Но рассмотрим утверждение (длина> 0). Таким образом, мы можем перевести это как «перепроверить длину больше нуля» или «убедиться, что длина больше нуля» . Хотя оба варианта работают четко, я все же предпочитаю свой;)
Blake7

4
Хорошо, но другая интерпретация такова: « сделайте длину больше нуля». Так что тут немного больше двусмысленности.
Люк Маурер

29
Это более близко аналогично английскому глаголу «утверждать»
Стив Картер

В самом деле, «убедитесь» можно интерпретировать как «проверить, а если нет, изменить».
Эрик Бонгерс

14

Взгляни на

Пример программы assert () на C ++

Многие компиляторы предлагают макрос 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

11
Не должно быть "если NDEBUG определен"?
RichN

2
О чем говорят многие компиляторы? MSVC и GCC оба соответствуют стандартам на этом. Какие несовместимые компиляторы: не имеют assert; не печатать сообщение и не прерывать работу при сбое подтверждения; использовать DEBUG вместо правильного NDEBUG?
Стив Джессоп

Имао, конечно, это веб-сайт под названием java-samples, который так ошибается.
underscore_d

6

Функция assert () может диагностировать программные ошибки. В C он определен в <assert.h>, а в C ++ - в <cassert>. Его прототип

void assert(int expression);

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

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

assert (Interest_rate> = 0); в местах в программе, где используется Interest_rate. Если переменная становится отрицательной, макрос 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

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

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


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

4

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

Вот интересное, немного другое значение 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
они следуют стандартному поведению
stijn

1

C ++ 11 N3337 стандартная версия

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

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

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

2 Содержимое совпадает с заголовком стандартной библиотеки 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)

Макрос assert переопределяется в соответствии с текущим состоянием NDEBUG при каждом <assert.h>включении.

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

7.2.1 Программа диагностики

7.2.1.1 Макрос утверждения

конспект

1.

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

Описание

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

Возвращает

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


1

Существует три основных причины использования функции assert () по сравнению с обычными if else и printf

  1. Функция assert () в основном используется на этапе отладки, и утомительно писать, если еще с оператором printf, каждый раз, когда вы хотите проверить условие, которое может даже не попасть в окончательный код.

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

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


0

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

Он предназначен для проверки сделанных вами предположений. Например:

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

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

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


почему мы просто не используем if & else и не добавляем информацию для регистрации?
Асад Хан

1
Потому что вы никогда не должны передавать пустой указатель на strcpy. Это одна из тех вещей, которые не должны происходить. Если нулевой указатель был передан, это означает, что что-то на более высоком уровне испортилось. В лучшем случае вам в конечном итоге приходится отказывать программе дальше от проблемы из-за неожиданных значений данных (либо dest неверно, либо null).
Якоби

-5

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

Пример кода:

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злое.
Гонки легкости на орбите

Да ты прав. Я забыл добавить не. Очень хотелось бы посмотреть, как ты будешь использовать вместо выхода
Садыков

1
@Sadikov Любой другой мог бы обработать такое состояние ошибки, используя код, который не был полностью удален при сборке в режиме выпуска , таким образом оставляя ваших пользователей без защиты и во власти неопределенного поведения, если предварительное условие не выполнено и, благодаря этому, выполняется ни разу не проверял и не ловил . assert()предназначен только для отладки и удаления вещей, которые никогда не должны происходить никогда - задолго до того, как будет выпущена сборка релиза.
underscore_d
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.