This paper illustrates the implementation process of C standard library <assert.h> and its related usage. Share to everyone for your reference. The specific analysis is as follows:
I. Background knowledge
Header file <assert.h> The sole purpose is to provide an Assert macro definition that you can use to make assertions in key areas of your program. If an assertion is proven to be true, you want the program to output an appropriate hint to the standard error stream and terminate the execution abnormally.
You can write code like this:
#include <assert.h> ...
ASSERT (0 <= i && i < sizeof (a)/sizeof (a[0)));
Of course, the above code is not the best form of combat, the program exception termination should be changed to some kind of error recovery.
Macro Ndebug
You can change how an assert expands by defining the macro ndebug in some parts of the program
If a program contains an assert where no ndebug is defined, the header defines the macro assert as an active form, it can expand into an expression, test the assertion and output an error message when the assertion is false, and the program terminates. Conversely, if ndebug is defined, the header file defines the macro as a static form that does not perform any action.
Second, the use of <assert.h>
As you can see from the above code, you can use a simple predicate to simplify the assert:
if (!ok)
abort ()///in header file <stdlib.h> declaration
If you find it necessary to assert that there is no existence, add the following code before the header file is included:
#define NDEBUG//Cancellation assertion
#include <assert.h>
Assertions can be controlled in different ways throughout the source file, and when assertions occur inside a frequently executed loop, performance can fall precipitously, or an earlier assertion may terminate the program before the prompt part is reached. To open an assertion, you can write:
#undef ndebug
#include <assert.h>
To turn off assertions, you can write:
#define NDEBUG
#include <assert.h>
Note: Even if the macro ndebug has been defined, we can still safely define it, which is a benign redefinition
Third, the realization of <assert.h>
From the analysis above, the general framework of the header file is as follows:
#undef assert//Remove the defined
#ifdef ndebug
#define ASSERT (expr) ((void) 0)//function failure
#else
#define ASSERT ( Expr) ...
#endif
A simple way to write the active form of a macro assert is as follows:
#define ASSERT (expr) if (!) ( expr) \
fprintf (stderr, "Assertion failed:%s, file%s, line%i\n", \
#expr, __file__, __line__)
This approach is not acceptable for several reasons:
1, the macro can not directly call any of the library output functions
The above definition contains functions or macros defined in stdio.h, such as fprintf, stderr, and the program may not contain this header file
2, the macro must be able to extend to a void type expression
3, the macro should be extended to effective and compact code
This version always calls a function that passes 5 arguments.
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
Where __line__ is a built-in macro that represents the line number of that line of code, and since __line__ does not expand into a string literal, it becomes a decimal constant, and converting it to the appropriate form requires an extra layer of processing. Add two hidden macros __str and __xstr to the header file, one of which replaces the __line__ with its decimal constant extension, and the other is converting the decimal constant to a string literal
The implementation of the hidden library function __bad_assertion the macro invocation:
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
void __bad_assertion ( const char *mess) {
fputs (mess, stderr);
Abort ();
}
The function __bad_assertion uses two other library functions, fputs the string to the standard error stream by invoking the function declared in <stdio.h>, and using the abort exception to terminate the execution of the program, the related header files will be analyzed in detail later.
Iv. <assert.h> Testing
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
int main (void)
{
FILE *FP;
fp = fopen ("Test.txt", "w"),//open a file in a writable manner, and create a file
assert (FP) with the same name if not present; So there's no mistake
fclose (FP);
fp = fopen ("Noexitfile.txt", "R");//Open a file as read-only, open file Failure
assert (FP) if not present; So here's the error
fclose (FP); The program will never execute here. return
0;
Attention:
1. Verify the validity of the incoming parameter at the beginning of the function such as:
int resetbuffersize (int nnewsize)
{//
function: Changing buffer size,
//parameter: Nnewsize buffer new length
//return value: Buffer current length/
//Say Ming: Keep The original information content unchanged nnewsize<=0 means to clear the buffer
assert (nnewsize >= 0);
ASSERT (Nnewsize <= max_buffer_size);
...
}
2. Each assert examines only one condition, because when multiple conditions are checked, if the assertion fails, it is not intuitive to determine which condition failed , such as:
ASSERT (noffset>=0 && noffset+nsize<=m_ninfomationsize);/
/bad/good
assert (noffset >= 0);
ASSERT (Noffset+nsize <= m_ninfomationsize);
3. You cannot use statements that alter the environment, because assert only takes effect in debug, and if you do so, you will experience problems with the program when it is actually running , such as:
Error:
This is because if an error occurs, such as i=100 before execution, then the statement is not executed, and i++ This command is not executed.
That's right:
The 4.assert and subsequent statements should be blank lines to form a logical and visually consistent sense.
5. In some places, assert cannot replace conditional filtering.
I believe that this article on the C programming for everyone to learn the value of a certain reference.