Что такое assert c
Перейти к содержимому

Что такое assert c

  • автор:

Что такое assert c

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

Одним из выходов из подобной ситуации является прекращение работы программы при возникновении критичной ошибки. Для этого в языке С может применяться функция assert() . Например:

void someFunc() < assert(checkСonditions() && "Error! Conditions are incorrect"); // основной код >

В данном коде assert() с помощью некоторой функции checkСonditions() проверяет некоторые условия, и если они не выполняются, assert() выводит в стандартный поток ошибок stderr сообщение «Error! Conditions are incorrect». И после этого выполнение программы прерывается.

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

Например, возьмем следующюю программу:

#include void writeTextToFile(char*, char*); int main(void) < char* filename = "test.txt"; char* text = "Hello METANIT.COM"; writeTextToFile(filename, text); >void writeTextToFile(char* file_name, char* text) < // проверка предусловий if(file_name==NULL) // если имя файла не указано, выход из функции < printf("Error! File name is incorrect!\n"); return; >if(text == NULL) // если текст не указан < printf("Error! Text is incorrect!\n"); return; >// открываем файл FILE* file_pointer=fopen(file_name, "w"); if(file_pointer == NULL) // если открытие файла прошло неудачно, выход из функции открыт < printf("Error! Unable to open file!\n"); return; >// запись в файл if(fputs(text, file_pointer)!=EOF) < printf("Success! Text has been written to the file!\n"); >// закрываем файл fclose(file_pointer); >

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

#include #include > // для функции assert void writeTextToFile(char*, char*); int main(void) < char* filename = "test.txt"; char* text = "Hello METANIT.COM"; writeTextToFile(filename, text); >void writeTextToFile(char* file_name, char* text) < // проверка предусловий assert(file_name!=NULL && "Error! File name is incorrect!\n"); // если имя файла не указано, выход из функции assert(text != NULL && "Error! Text is incorrect!\n"); // если текст не указан // открываем файл FILE* file_pointer=fopen(file_name, "w"); if(file_pointer == NULL) // если открытие файла прошло неудачно, выход из функции открыт < printf("Error! Unable to open file!\n"); return; >// запись в файл if(fputs(text, file_pointer)!=EOF) < printf("Success! Text has been written to the file!\n"); >// закрываем файл fclose(file_pointer); >

Таким образом, если выполняются условия file_name!=NULL и text != NULL , то функция продолжает свою работу — записывает строку в файл. Если хотя бы одно из условий не выполняется, то функция завершает работу, а на консоль выводится сообщение. Например, если file_name = 0, выводится сообщение следующего типа:

Assertion failed: file_name!=NULL && "Error! File name is incorrect!\n", file app.c, line 15

assert макрос, _assert , _wassert

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

Синтаксис

assert( expression ); void _assert( char const* message, char const* filename, unsigned line ); void _wassert( wchar_t const* message, wchar_t const* filename, unsigned line ); 

Параметры

expression
Скалярное выражение (включая выражения указателя), которое возвращает ненулевое значение ( true ) или 0 ( false ).

message
Отображаемое сообщение.

filename
Имя файла исходного кода, в котором произошел сбой утверждения.

line
Номер строки в файле исходного кода, в которой произошел сбой утверждения.

Замечания

Макрос assert обычно используется для выявления ошибок логики во время разработки программы. Используйте его для остановки выполнения программы при возникновении непредвиденных условий. Для этого реализуйте аргумент expression так, чтобы он принимал значение false только в том случае, если программа работает неправильно. Проверки утверждения можно отключить во время компиляции, определив макрос NDEBUG . Макрос можно отключить assert без изменения исходных файлов с помощью параметра командной /DNDEBUG строки. Вы можете отключить assert макрос в исходном #define NDEBUG коде с помощью директивы перед включением.

Макрос assert выводит диагностическое сообщение при expression оценке (0) и вызовы false abort для остановки выполнения программы. Если значение expression равно true (отлично от нуля), никаких действий не выполняется. Диагностическое сообщение включает выражение, где произошел сбой, имя файла исходного кода и номер строки, со сбоем утверждения.

Диагностическое сообщение выводится в широких ( wchar_t ) символах. Таким образом, он будет работать должным образом, даже если в выражении есть символы Юникода.

Назначение диагностического сообщения зависит от типа приложения, которое вызвало подпрограмму. Консольные приложения получают сообщение через stderr . В приложении assert под управлением Windows вызывает функцию Windows MessageBox , чтобы создать окно сообщения, чтобы отобразить сообщение с тремя кнопками: Прерывание, повторная попытка и игнорировать. Если пользователь выбирает прерывание, программа прерывается немедленно. Если пользователь выбирает повторную попытку, то вызывается отладчик, и пользователь может отладить программу, если включена JIT-отладка. Если пользователь выберет «Игнорировать», программа продолжит нормальное выполнение. Нажатие кнопки «Игнорировать» , если условие ошибки существует, может привести к неопределенному поведению, так как предварительные условия вызывающего кода не были выполнены.

Чтобы переопределить поведение выходных данных по умолчанию независимо от типа приложения, вызовите _set_error_mode выбор между поведением вывода к stderr и display-dialog-box.

После assert отображения сообщения он вызывает abort диалоговое окно с кнопками «Прерывание«, «Повтор» и «Игнорировать «. abort завершает программу, поэтому кнопка «Повторить» и «Игнорировать« не возобновляет выполнение программы после assert вызова. Если assert отображается диалоговое окно, abort диалоговое окно не отображается. Единственное время отображения диалогового abort окна — при assert отправке выходных данных в stderr.

В результате приведенного выше поведения диалоговое окно всегда отображается после вызова в режиме assert отладки. Поведение каждой кнопки фиксируется в приведенной ниже таблице.

Режим ошибки stderr Выходные данные в (консоль/ _OUT_TO_STDERR ) Диалоговое окно отображения (Windows/ _OUT_TO_MSGBOX )
Abort Немедленное завершение работы с кодом выхода 3 Немедленное завершение работы с кодом выхода 3
Retry Разрыв в отладчике во время abort Разрыв в отладчике во время assert
Ignore Завершение выхода через abort Продолжить программу, как будто assert не срабатывает (может привести к неопределенному поведению, так как предварительные условия вызывающего кода не были выполнены)

Дополнительные сведения об отладке CRT см. в статьях о методах отладки CRT.

Функции _assert и _wassert являются внутренними функциями CRT. Они позволяют свести к минимуму объем кода, требуемый в объектных файлах для поддержки утверждений. Мы не рекомендуем вызывать эти функции напрямую.

Макрос assert включен как в выпусках, так и в отладочных версиях библиотек времени выполнения C, если NDEBUG они не определены. Если NDEBUG определено, макрос доступен, но не оценивает его аргумент и не влияет. Когда он включен, assert макрос вызывает _wassert его реализацию. Другие макросы утверждения, _ASSERT _ASSERTE а _ASSERT_EXPR также доступны, но они оценивают только выражения, передаваемые им, когда _DEBUG макрос определен и когда они находятся в коде, связанном с отладочной версией библиотек времени выполнения C.

Требования

Маршрут Обязательный заголовок
assert , _wassert

Подпись _assert функции недоступна в файле заголовка. Подпись _wassert функции доступна только в том случае, если NDEBUG макрос не определен.

Пример

В этой программе функция analyze_string использует макрос assert для проверки нескольких условий, связанных со строкой и длиной. Если какое-либо из условий не выполняется, программа выводит сообщение, указывающее на причину сбоя.

// crt_assert.c // compile by using: cl /W4 crt_assert.c #include #include #include void analyze_string( char *string ); // Prototype int main( void ) < char test1[] = "abc", *test2 = NULL, test3[] = ""; printf ( "Analyzing string '%s'\n", test1 ); fflush( stdout ); analyze_string( test1 ); printf ( "Analyzing string '%s'\n", test2 ); fflush( stdout ); analyze_string( test2 ); printf ( "Analyzing string '%s'\n", test3 ); fflush( stdout ); analyze_string( test3 ); >// Tests a string to see if it is NULL, // empty, or longer than 0 characters. void analyze_string( char * string ) < assert( string != NULL ); // Cannot be NULL assert( *string != '\0' ); // Cannot be empty assert( strlen( string ) >2 ); // Length must exceed 2 > 

Программа создает следующие выходные данные:

Analyzing string 'abc' Analyzing string '(null)' Assertion failed: string != NULL, file crt_assert.c, line 25 

После сбоя утверждения в зависимости от версии операционной системы и библиотеки времени выполнения может отображаться окно сообщения, содержащее примерно следующее:

A problem caused the program to stop working correctly. Windows will close the program and notify you if a solution is available. 

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

Что такое assert c

В некоторых программах присутствуют вызовы assert (или ASSERT). В этой статье собрана информация из разных источников, поясняющая смысл и принцип использования этой операции на языке C/C++.

«Assert» в переводе с английского означает «утверждать». В контексте программирования на C/C++ вызов assert означает, что какое-то условие в этом месте обязательно верно, и если это не так, то дальнейшее выполнение программы невозможно. Таким образом, assert прервет нормальную работу программы (иногда с выводом сообщения, которое указано в дополнительном параметре аргумента assert), если условие, которое проверяет assert, равно false. Обычно эта техника используется только для отладки (код assert компилируется только для конфигурации Debug проекта), чтобы отследить возможные проблемные места в программе.

Прототип функции assert() часто выглядит так (обычно это макрос):

void assert (int expression);

Если аргумент expression этого макроса вычисляется как 0 (т. е. становится false), то нормальный поток вычислений останавливается. Если это среда выполнения PC, то при этом в стандартный поток ошибок (stderr) будет выведено сообщение об ошибке, и будет вызвана функция abort, завершающая выполнение программы.

Специфика содержания сообщения зависит от конкретной реализации библиотеки кода реального времени выполнения (runtime library), но обычно подразумевается, что оно должно включать в себя как минимум выражение, которое ошибочно, имя модуля исходного кода, где произошла ошибка, и номер строки, где эта ошибка произошла. Простейшая реализация библиотеки (например, во встраиваемых приложениях) может вообще не генерировать сообщение об ошибке. Пример обычного формата сообщения об ошибке:

Assertion failed: выражение, имя_файла, номер_строки_файла

Функционал макроса становится доступен в момент подключения заголовочного файла assert.h. Если в момент подключения заголовка определено имя NDEBUG, то весь код операторов assert из программы выбрасывается. Это позволяет программисту на этапе отладки вставлять в код множество избыточных проверок, и впоследствии запретить их все, когда выпускается рабочий релиз программы. Это делается простым добавлением в код следующего определения (непосредственно перед подключением заголовочного файла assert.h):

#define NDEBUG 

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

Пример использования assert:

#include /* определение printf */
#include /* определение assert */
void print_number(int* myInt) < assert (myInt!=NULL); printf ("%d\n",*myInt); >
int main () < int a=10; int *b = NULL; int *c = NULL;
// Этот вызов функции отработает нормально: print_number (b); // Здесь произойдет срабатывание проверки assert: print_number (c);
return 0; >

Когда параметр assert становится false (в данном примере происходит, если передаваемый в функцию print_number указатель равен NULL), программа останавливается. Будет выведено сообщение об ошибке, и работа программы прервется.

Во встраиваемых приложениях остановка программы по ошибке в assert обычно заключается в бесконечном зацикливании в том месте кода, где проверка assert показала ошибку. Для диагностики ошибки можно остановить выполнение в отладчике, и посмотреть, в каком месте программы произошло зацикливание. Реже реализация assert предусматривает дополнительный параметр в виде текстового сообщения, которое поясняет причину возникновения ошибки. Это сообщение обычно выводится в отладочную консоль (на экран или в последовательный порт UART). Пример:

assert("Длина не может быть отрицательна!", length >= 0);

Когда выпускается релиз проекта (конфигурация Release), то все вычисления, связанные с проверками assert, из программы удаляются. Это делается с помощью операторов условной компиляции путем проверки наличия макроопределения наподобие NDEBUG, NODEBUG, DEBUG и т. п. Будьте внимательны: программа никогда не должна полагаться на запуск кода в проверках assert, иначе релиз нормально работать не будет.

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

Как использовать assert? Достаточно следовать нескольким простым правилам:

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

2. Не пишите программу так, что её выполнение зависит от кода assert(). Например, следующий вызов assert будет ошибочным:

assert(++length >= 0);

Вместо этого следует писать так:

++length; assert(length >= 0);

Причина понятна — в релизе код assert будет выброшен, так что length не получит инкремента. В результате программа будет работать по-другому, если будет работать вообще.

3. Всегда проверяйте, что для релиза код assert() выбрасывается из исполняемого кода.

[Что внутри assert?]

В зависимости от среды разработки, языка, подключенных библиотек и определений тело assert может работать по-разному. Например, в приложении PC на языке C++ может вызываться исключение (throw/raise excepton), на языке C может происходить останов выполнения программы с выходом (abort, exit). Во встраиваемых приложениях (микроконтроллеры) обычной практикой реализации assert может быть простое бесконечное зацикливание, иногда это реализуется с выводом подходящего сообщения в последовательный порт (отладочную консоль, UART).

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

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

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

#ifndef NDEBUG // При ошибке (если expr==false) произойдет зависание в бесконечном цикле:
 #define MYASSERT(expr) if (!(expr)) while(1)
#else // В конфигурации релиза код MYASSERT будет выброшен:
 #define MYASSERT(expr)
#endif 

[Ссылки]

1. Assertion (software development) site:wikipedia.org.
2. What is the “assert” function? site:stackoverflow.com.
3. Assert. Что это? site:habrahabr.ru.

assert: функция сообщения об ошибке в С++

Функция assert оценивает выражение, которое передается ей в качестве аргумента, через параметр expression . Если аргумент-выражение этого макроса в функциональной форме равно нулю (т.е. выражение ложно), сообщение записывается на стандартное устройство вывода ошибок и вызывается функция abort , работа программы прекращается.

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

filename: line number: expression: аssertion failed:
#define NDEBUG // в начале файла исходного кода, перед включением заголовочного файла

Параметры:

  • expression
    Выражение для оценки. Если логическое выражение в параметре expression равно 0, функция assert немедленно завершает программу.

Возвращаемое значение

Пример: исходный код программы

// пример использования функции assert #include // для оператора cout #include // для функции assert void print_adds(int* value) < assert(value != NULL); std::cout int main() < int a = 10; int *ptr1 = &a; // указатель на переменную a int *ptr2 = NULL; // нулевой указатель print_adds(ptr1); // вызов функции с ненулевым указателем print_adds(ptr2); // вызов функции с нулевым указателем return 0; >

Пример работы программы

В этом примере, функция assert используется, чтобы прервать выполнение программы, если функции print_adds в качестве аргумента передаётся нулевой указатель. В программе, первый вызов функции print_adds завершается успешно. Второй вызов, в качестве аргумента, принимает нулевой указатель ptr2 . И как раз в этот момент срабатывает функция assert , она оценивает выражение, в данном случае нулевой указатель. Нулевой указатель не указывает ни на какой блок памяти, поэтому assert сигнализирует об ошибке и немедленно завершает работу программы.

CppStudio.com

Адрес значения в памяти = 0x7fff5900f8ac
er: ../er/main.cpp:7: void print_adds(int*): Assertion `value != __null’ failed.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *