URL: http://www.cnblogs.com/archimedes/p/c-library-assert.html.
1. Background Knowledge
The only purpose of the header file <assert. h> is to provide the assert macro definition, which can be used for assertions in key areas of the program. If an asserted proves to be untrue, you want the program to output an appropriate prompt in the standard error stream and terminate the execution.
You can write the code as follows:
#include<assert.h>...assert(0 <= i && i < sizeof(a) / sizeof(a[0]));
Of course, the above Code is not the best form in practice. The exceptional termination of the program should be changed to the recovery of some errors.
Macro NDEBUG
You can define the macro NDEBUG in some places of the program to change the assert expansion mode.
If NDEBUG is not defined for a place in the program that contains assert, the header file defines the macro assert as an active form and can be expanded into an expression, test the assertion and output an error message when the assertion is false, and the program ends. If NDEBUG is defined, the header file defines this macro as a static form without any operations.
2. Use of <assert. h>
From the code above, we can see that a simple predicate can be used to simplify assert:
If (! OK) abort (); // declare it in the header file <stdlib. h>
If you think there is no need for assertions, add the following code before including the header file:
# Define NDEBUG // cancel assertion # include <assert. h>
Different methods can be used to control assertions in the entire source file. When assertions occur within a frequently executed loop, the performance may drop sharply or before reaching the suggestive part, an earlier asserted may terminate the program. To enable assertions, you can write:
#undef NDEBUG#include<assert.h>
To disable assertions, you can write:
#define NDEBUG#include<assert.h>
Note: even if the macro NDEBUG has been defined, we can still define it safely, which is a benign redefinition.
3. Implementation of <assert. h>
According to the above analysis, the general framework of this header file is as follows:
# Undef assert // remove defined # ifdef NDEBUG # define assert (expr) (void) 0) // function failure # else # define assert (expr )... # endif
A Simple Method for writing macro assert activities is as follows:
#define assert(expr) if(!(expr)) \ fprintf(stderr, "Assertion failed: %s, file %s, line %i\n", \ #expr, __FILE__, __LINE__)
This method is unacceptable for the following reasons:
1. Macros cannot directly call any output functions of the database.
The above definition contains fprintf, stderr, and other functions or macros defined in stdio. h. The program may not contain this header file.
2. The macro must be extended to a void expression.
3. Macros should be able to be extended to effective and compact code
In this version, a function with five parameters is always called.
The modified assert macro is as follows:
#undef assert#ifdef NDEBUG #define assert(expr) ((void) 0)#else void __bad_assertion (const char *_mess); #define __str(x) # x #define __xstr(x) __str(x) #define assert(expr) ((expr)? (void)0 : \ __bad_assertion("Assertion \"" #expr \ "\" failed, file " __xstr(__FILE__) \ ", line " __xstr(__LINE__) "\n"))#endif
Here, _ LINE _ is a built-in macro that represents the row number of the code for this row. Because _ LINE _ is not extended to the string literal, it becomes a decimal constant, converting it to an appropriate form requires an additional processing layer. Add two hidden macros _ str and _ xstr to the header file. One macro replaces _ LINE __with its decimal constant extension __, the other is to convert a decimal constant into a string literal.
Implementation of the hidden library function _ bad_assertion called by a macro:
#include<assert.h>#include<stdio.h>#include<stdlib.h>void __bad_assertion(const char *mess) { fputs(mess, stderr); abort(); }
Function _ bad_assertion uses two other library functions by calling <stdio. h> the function fputs declared in writes the string to the standard error stream and terminates the program execution with abort exceptions. The relevant header files will be analyzed in detail later.
4. <assert. h> Test
# Include <assert. h> # include <stdio. h> # include <stdlib. h> int main (void) {FILE * fp; fp = fopen ("test.txt", "w"); // open a FILE in writable mode, create a file with the same name as assert (fp) if it does not exist; // No error is found here: fclose (fp); fp = fopen ("noexitfile.txt", "r "); // open a file in read-only mode. If the file does not exist, assert (fp) fails to be opened. // The fclose (fp) error occurs here ); // The program will never be executed here to return 0 ;}
Note:
1. Check the validity of input parameters at the beginning of the function, for example:
Int resetBufferSize (int nNewSize) {// function: Change the buffer size, // parameter: New length of the nNewSize buffer // return value: current length of the buffer // description: nNewSize <= 0 indicates clearing the buffer assert (nNewSize> = 0); assert (nNewSize <= MAX_BUFFER_SIZE );...}
2. Each assert tests only one condition, because when multiple conditions are verified simultaneously, if the assert fails, you cannot intuitively determine which condition fails, for example:
Assert (nOffset> = 0 & nOffset + nSize <= m_nInfomationSize); // poor // good assert (nOffset> = 0); assert (nOffset + nSize <= m_nInfomationSize );
3. You cannot use statements that change the environment, because assert takes effect only on DEBUG. If you do so, problems will occur when the program is actually running, such:
Error:
assert(i++ < 100);
This is because if an error occurs, for example, I = 100 before execution, this statement will not be executed, and the I ++ command will not be executed.
Correct:
assert(i < 100);i++;
4. The assert and subsequent statements should be empty in a row to form a logical and visual sense of consistency.
5. In some cases, assert cannot replace conditional filtering.
References
C Standard Library