assert - как пользоваться, и каким образом эта вещь работает?

Тема в разделе "LANGS.C", создана пользователем varnie, 31 окт 2007.

  1. varnie

    varnie New Member

    Публикаций:
    0
    Регистрация:
    2 янв 2005
    Сообщения:
    1.785
    добрый день!

    постепенно прививаю себе одну полезную фичу С++ за другой, как только с ней разберусь. настал черед и assert(), но все никак не могу до конца понять, каким образом assert() действует в _не_ дебуг версии откомпиленной программы? насколько я понимаю (могу ошибаться, поправьте пожалуйста если это так), код макроса assert() включается только в дебуг версию приложения, и в случае невыполнения условия в assert-e происходит корректное завершение программы. если это все верно, то как assert помогает в релиз-версиях программы?
    допустим, есть след. кусок кода:
    Код (Text):
    1. inline void Array::Elem(int i)
    2. {
    3.     assert(i>=0 && i<len);
    4.     return val[i];
    5. }
    как эта вставка assert в этом методе поможет корректному отрабатыванию этого метода в релиз версии программы?
    поясните, кому не сильно долго:)
     
  2. Cr4sh

    Cr4sh New Member

    Публикаций:
    0
    Регистрация:
    17 апр 2006
    Сообщения:
    668
    в релиз-версии никак, в дебаг-версии прога будет брякаться по int 3
    асерты обычно ставят в тех местах, куда входящие данные не передаются извне, и где впринципе ни при каких обстоятельствах не может быть исключений
     
  3. varnie

    varnie New Member

    Публикаций:
    0
    Регистрация:
    2 янв 2005
    Сообщения:
    1.785
    Cr4sh,
    понятно. но меня смущает вот эта выдержка из "man assert":
    получается, что этот макрос может быть удален во время компиляции, но не обязан --> этот макрос может присутствовать в релиз вершн программы. и вообще, тон этой выдержки какбы говорит о том, что по-дефолту этот макрос не удаляется во время компиляции.
    или я не так интерпретирую эту выдержку?

    и если в релиз вершне этот макрос никак не проявляется, то зачем же его юзать? чтобы отловить бОльшую часть потенциальных багов в дебуг вершне и надеяться что далее в релизе их уже не будет?:)

    обратимся к куску кода в посте#1. почему программист может спать спокойно, включив эту строчку с ассертом в этот метод выше? ведь в релиз вершне ассерта уже не будет, и следовательно, запрошенный по индексу элемент массива не факт что будет удовлетворять границам массива, и будет серьезный баг.
    что на этот счет можете сказать? спасибо!.
     
  4. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    Собственно, в справке всё сказано:
    Как работает — посмотри сорцы и в отладчике. Или тебе неясен сам макрос?

    Наоборот, возникает исключительная ситуация вследствие нарушения утверждения (assert'a) и показывается соответствующее окошко. При нажатии на кнопку "Повторить" подключается отладчик и можно работать с ним.

    Утверждения помогают только при отладке, в релизе их нет. Для последнего есть макрос VERIFY, но использовать его надо с умом, а лучше делать свои проверки и корректное завершение операций в случае нарушения их.

    Так.

    Просто надо помнить, что отладочные средства — это не панацея.
     
  5. varnie

    varnie New Member

    Публикаций:
    0
    Регистрация:
    2 янв 2005
    Сообщения:
    1.785
    IceStudent,
    а что это за справка? только не говорите что это из MSDN, у меня нету Виндовс.

    окей, с дебуг-вершн теперь прояснилось, спасибо вам, IceStudent.

    осталось разобраться с релиз-вершн. процитирую самого себя:
    или же правильнее написать что-то типа:
    Код (Text):
    1. inline void Array::Elem(int i)
    2. {
    3.     assert(i>=0 && i<len);
    4.     if ( i <= 0 || i > len )    //прописали проверку на границы явно
    5.         return;
    6.  
    7.     return val[i];
    8. }
    для того чтобы не беспокоиться за выход за границы в массиве в релиз-вершн программы?
     
  6. roman_pro

    roman_pro New Member

    Публикаций:
    0
    Регистрация:
    9 фев 2007
    Сообщения:
    291
    http://msdn.microsoft.com/library/
     
  7. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    varnie
    Схватываешь на лету.
     
  8. censored

    censored New Member

    Публикаций:
    0
    Регистрация:
    5 июл 2005
    Сообщения:
    1.615
    Адрес:
    деревня "Анонимные Прокси"
    Код (Text):
    1. if (i<0 || i>=len)
     
  9. mathio

    mathio New Member

    Публикаций:
    0
    Регистрация:
    16 июн 2007
    Сообщения:
    110
    А еще можно определить такой макрос assert():
    Код (Text):
    1. #define STATIC_ASSERT(X)  extern int _ass_ert_[ ( (X) != 0 ) * 2 - 1 ];
    Он будет валиден для проверок времени трансляции. Тоесть например, для сравнения типов и размерности структур/массивов.
    Имя _ass_ert_(в данном случае) также часто завязывают на всякие компайлер-зависимые рендомайзеры, вроде __LINE__, __FILE__ и т.д., дабы исключить их возможное повторное появление в большом проекте.
     
  10. nester7

    nester7 New Member

    Публикаций:
    0
    Регистрация:
    5 дек 2003
    Сообщения:
    720
    Адрес:
    Russia
    mathio
    А можно чуть подробнее про вышеприведённый макрос, желательно с парой примеров,
    а то я что-то подвис на фразе "для сравнения типов".
     
  11. mathio

    mathio New Member

    Публикаций:
    0
    Регистрация:
    16 июн 2007
    Сообщения:
    110
    Правильнее, "размерности" типов, my mistake ;)

    Ну, а примеров всяких до кучи можно привести

    Код (Text):
    1. typedef struct
    2. {
    3.   int   a;
    4.   char  b;
    5.   short c;
    6. } aaa;
    7.  
    8. typedef struct
    9. {
    10.   int  a;
    11.   char b;
    12.   int  c;
    13. } bbb;
    14.  
    15. aaa _a;
    16. bbb _b;
    17.  
    18. STATIC_ASSERT(sizeof(_a) == sizeof(_b))
    или
    Код (Text):
    1. #pragma pack(push, 1)
    2. typedef struct
    3. {
    4.   int   a;
    5.   char  b;
    6.   short c;
    7. } aaa2;
    8. #pragma pack(pop)
    9.  
    10. #pragma pack(push, 8)
    11. typedef struct
    12. {
    13.   int   a;
    14.   char  b;
    15.   short c;
    16. } aaa3;
    17. #pragma pack(pop)
    18.  
    19. aaa2 _a2;
    20. aaa3 _a3;
    21.  
    22. STATIC_ASSERT(sizeof(_a2) == sizeof(_a3))
     
  12. nester7

    nester7 New Member

    Публикаций:
    0
    Регистрация:
    5 дек 2003
    Сообщения:
    720
    Адрес:
    Russia
    mathio
    Понял, спасибо.
     
  13. varnie

    varnie New Member

    Публикаций:
    0
    Регистрация:
    2 янв 2005
    Сообщения:
    1.785
    censored,
    да, верно. я сначала неправильно написал.

    IceStudent,
    раз мы явно прописываем проверку в теле ф-ции-члена, то почему вот в этой теме ,напротив, дали мне понять, что ошибки нет?
    хочу все по полочкам расставить, because i am curious :)
     
  14. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    varnie
    Во-первых, никто не заставляет делать проверки и её отсутствие не является ошибкой. Но качество софта будет на твоей совести. Во-вторых, есть различие между написанием кода для библиотеки и непосредственно программы, и различие заключается в контексте.

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

    Применительно к #5 можно сделать следующий вывод: если известно, что входные данные корректны (их проверка есть выше явно либо в виде условия цикла (for(; i < len;)), то нет смысла делать ещё одну проверку.