C Standard library <assert.h> Implementation of the detailed _c language

Source: Internet
Author: User

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:

ASSERT (i++ < 100);

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:

ASSERT (I < m);
i++;

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.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.