Що таке функція “ствердження”?


261

Я вивчав уроки OpenCV і натрапив на assertфункцію; що воно робить?


20
Зауважте зауваження від man assert: "assert () реалізований у вигляді макросу; якщо випробуваний вираз має побічні ефекти, поведінка програми буде відрізнятися залежно від того, визначено NDEBUG. Це може створити Heisenbugs, які відходять при включенні налагодження . "
Йоханнес Шауб - ліб


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

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

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

Відповіді:


297

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макрос, як правило, за допомогою компілятора компілятора. Наслідком цього є те, що ваша програма ніколи не повинна покладатися на запущений макрос затвердження.

// 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 ++ він не збільшується "виняток", він називає аборт ... він трохи інший.
Артем

5
Я не думаю, що ця відповідь є приблизно тими ж мовами, що і питання позначено тегами (C і C ++). У C і C ++, аствердження не викликає винятку, він має круглі дужки навколо свого аргументу, і #символ не вводить коментар.
Стів Джессоп

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

2
length> = 0 також вийде помилковим, якщо довжина NaN
Андреас

1
Наразі у VS 2015 збірка із повідомленням про помилку не працюватиме, оскільки вона вийшла з ладу. Це повинно бутиassert("error message", expression)
Dooskington

102

Стверджують , комп'ютер твердження аналогічно висловом переконайтеся , що на англійській мові.


131
Ну, не зовсім. "Переконайтеся, що світло вимкнено" означає "перевірити світло та вимкнути його, якщо він увімкнено", а не "побачити, чи світло вимкнено, а якщо ні, не вибухне". Я б сказав, що "подвійна перевірка" - це більш близький переклад.
Лука Маурер

7
@Luke, що ілюструє чудеса англійської мови, оскільки мова пропонує багато способів сказати те саме. Але розглянемо ствердження (довжина> 0). Тож ми можемо перекласти це, щоб "подвійно перевірити довжину більше нуля" або "переконатися, що довжина більше нуля" . Хоча явно обидва варіанти працюють, я все ще віддаю перевагу своєму;)
Blake7,

4
Ну, але інше тлумачення - " зробіть довжину більше нуля". Тож є дещо більше неоднозначності.
Люк Маурер

29
Це ближче аналогічно англійському дієслову "assert"
Стів Картер

Дійсно, «переконайтесь» можна інтерпретувати як «перевірити, а якщо не гаразд - змінити».
Ерік Бонгерс

14

Подивись на

Приклад програми assert () в C ++

Багато компіляторів пропонують макрос assert (). Макрос assert () повертає TRUE, якщо його параметр оцінює TRUE та виконує якусь дію, якщо він оцінює FALSE. Багато компіляторів скасують програму, якщо не вдасться; інші кинуть виняток

Однією з потужних особливостей макросу assrt () є те, що препроцесор згортає його взагалі без коду, якщо 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 обидва стандарти відповідають цьому. Які невідповідні компілятори: не мають стверджувати; не друкуйте повідомлення та не переривайте, якщо скарга не вдається; використовувати DEBUG замість належного NDEBUG?
Стів Джессоп

lmao, звичайно, це так називається веб-сайт під назвою java-sample .
підкреслюй_d

6

Функція assert () може діагностувати програмні помилки. У C він визначений у <assert.h>, а в C ++ - у <cassert>. Її прототип є

void assert(int expression);

Вираз аргументу може бути будь-яким, що ви хочете перевірити - змінним або будь-яким виразом C. Якщо вираз оцінюється як ІСТИНА, assert () нічого не робить. Якщо вираз оцінюється на FALSE, assrt () відображає повідомлення про помилку при виконанні програми stderr і перериває виконання програми.

Як ви використовуєте assert ()? Він найчастіше використовується для відстеження програмних помилок (які відрізняються від помилок компіляції). Помилка не заважає програмі компілювати програму, але вона призводить до неправильних результатів або неправильного запуску (наприклад, блокування). Наприклад, програма фінансового аналізу, яку ви пишете, може періодично давати неправильні відповіді. Ви підозрюєте, що проблема викликана тим, що змінна interest_rate приймає негативне значення, що ніколи не повинно відбуватися. Щоб перевірити це, поставте заяву

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

Щоб побачити, як працює assrt (), запустіть зразок програми нижче . Якщо ви введете ненульове значення, програма відображає це значення і нормально припиняється. Якщо ви введете нуль, макрос assrt () примушує ненормальне завершення програми. Точне повідомлення про помилку, яке ви побачите, залежатиме від вашого компілятора, але ось типовий приклад:

Не вдалося стверджувати: x, список файлів19_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

Повідомлення про помилку: ненормальне завершення програми

Ваше повідомлення про помилку може відрізнятися залежно від вашої системи та компілятора, але загальна ідея та ж.


Ви пояснили, як працює зразок програми з утвердженням. Не так, як працює сама утвердження. Як це закінчується програмою ненормально? це кидає якийсь виняток? Який? Чи створює це спеціальний сигнал? який сигнал? Чи можуть твердження «зачепитися» за допомогою будь-якого механізму спроб уловлювання C ++?
Motti Shneor

4

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

Ось цікавий, дещо інший сенс затвердження, що використовується c6x та іншими компіляторами TI: побачивши певні заяви твердження, ці компілятори використовують інформацію в цьому операторі для здійснення певних оптимізацій. Злий.

Приклад в 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
Отже, що вони роблять, якщо аргумент хибний, а NDEBUG не встановлений? Якщо це версія assrt від <assert.h>, то стандарт вимагає, щоб він надрукував повідомлення та скасував. Очевидно, стандарт не говорить про те, що їм не дозволяється проводити оптимізацію на основі істинності твердження, але щоб бути сумісними, вони все одно повинні перервати, якщо це неправдиво.
Стів Джессоп

1
вони дотримуються стандартної поведінки
стинь

1

C ++ 11 стандартна тяга N3337

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

19.3 твердження

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

2 Вміст такий самий, як у заголовку бібліотеки Standard C <assert.h>.

C99 N1256 стандартна тяга

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

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

1 Заголовок <assert.h>визначає макрос затвердження і посилається на інший макрос, NDEBUGякий не визначений <assert.h>. Якщо NDEBUGвизначено як ім'я макросу в точці вихідного файлу, куди включено <assrt.h>, макрос assert визначається просто як

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

Макрос затвердження перевизначається відповідно до поточного стану NDEBUG кожного разу, коли <assert.h>він включається.

2. Макрос затвердження повинен бути реалізований як макрос, а не як фактична функція. Якщо визначення макросу придушено для доступу до фактичної функції, поведінка не визначена.

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

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

Конспект

1.

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

Опис

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

Повертається

3 Макрос затвердження не повертає значення.


1

Існує три основні причини використання функції assrt () над звичайною, якщо інше і printf

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

  2. У великих розгортаннях програмного забезпечення asrt стає дуже зручним, коли ви можете змусити компілятор ігнорувати заяви заяви, використовуючи макрос NDEBUG, визначений перед тим, як зв’язати файл заголовка для функції assert ().

  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++);
}

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


чому ми просто не використовуємо if & else і додаємо інформацію про реєстрацію?
Асад Хан

1
Тому що ви ніколи не повинні передавати нульовий вказівник на strcpy. Це одна з тих речей, яка не повинна статися. Якщо нульовий покажчик був переданий, це вказує на те, що щось на більш високому рівні переплуталося. У кращому випадку вам доведеться збоїти програму далі від проблеми через несподівані значення даних (або dest, невірні, або нульові).
Якобі

-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()тільки для налагодження і викорінення речі , які ніколи, ніколи НЕ повинні ніколи трапитися - задовго до того, як побудувати реліз.
підкреслюй_d
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.