Explore the little secret assertions of C

  • 2020-04-02 01:40:03
  • OfStack

Every time I write an abstract, I find it a headache, because I know that the abstract is really important, and it almost directly determines the number of readers. May spent force of the tiger 962 written things, because of the failure and lost, because the vast majority of readers see articles before will browse the summary, if they find the "mismatch", there is no feature and attraction, so light, adopts the method of quick read the full text, or to found guilty of "death", the article the stand or fall of an article, though cannot be measured by the reader but it is often used to measure the stand or fall of an article, becoming the articles readers number one of the key factors. Now for assertions, I don't think many people would use assertions in their code if they were just learning C for general purposes, for exams, maybe some people have never used assertions before. So what does the use of assertions really bring to our code? I've tried to be as clear as possible about the use of assertions as I understand them, and I hope that the assertions I've presented here will help you to be more flexible with assertions in your code in the future.

Before we go on, let's give you a basic introduction to assertions to give you a general idea of them. When writing engineering code in C, we always check for assumptions that assertions are used to capture in the code, and you can think of assertions as a high-level form of exception handling. Assertions are expressed as Boolean expressions that the programmer believes to be true at a particular point in the program. Assertion validation can be enabled and disabled at any time, so assertions can be enabled at test time and disabled at deployment time. Similarly, once the program is in operation, the end user can revert to assertions when encountering problems. It can quickly find and locate software problems and automatically alarm system errors. Assertions can be used to locate problems that are hidden deep in the system and are extremely difficult to find by other means, so as to shorten the locating time of software problems and improve the testability of the system. In practice, assertions can be designed flexibly according to the specific situation.

Now that we have a general idea of assertions, let's look at the use of assert macros in C in our code.

Prototype definition:
Void assert(int expression);

The assert macro prototype is defined in < Assert. H > If the value of expression is false (that is, 0), it first prints an error message to stderr and then terminates the program by calling abort.

Here's a look at some of the code:


#include <stdio.h>
#include <assert.h>
int main( void )
{
      int i;
   i=1;
   assert(i++);

   printf("%dn",i);
       return 0;
}

The running result is:

< img Alt = "" border = 0 SRC =" / / files.jb51.net/file_images/article/201309/201309230908342.gif ">

Look at the results of the run, since we gave an initial value of I of 1, we use assert(I ++); I++ is executed, so the output value of the printed statement is 2. If we change the initial value of I to 0, the following error occurs.
Assertion failed: i++, file E:\fdsa\assert2.cpp, line 8
Press any key to continue

Do you find that you can quickly locate an error point based on the prompt? ! Since assert is so easy to locate, it seems appropriate to be familiar with using it in your code, but there are rules to everything, and assert is no exception.

Assertion statements are not always executed, and can be masked or enabled, which requires that assert should not affect the functionality of our own code in either the case of shielding or enabling it. In this case, we just used an assert(i++) in our code; It is improper, because once we disable assert, the statement of I ++ will not be executed, and there will be problems with the use of the value of I. Therefore, we should implement this statement separately. Write the following two sentences to replace assert(I); I++; , so there are corresponding requirements for the use of assertions, so when do we generally use assertions? Mainly reflected in the following aspects:

1. You can place assertions where the program is not expected to normally arrive. (such as assert (0);)

2. Preconditions and postconditions for execution using assertions test methods.

3. Use assertions to check the invariant state of a class, ensuring that in any case, the state of a variable must be satisfied. (such as the range of a variable)

For those of you who are not familiar with the preconditions and postconditions above, take a look at the following explanation.

Conditional assertion: a feature that must be present before code can be executed

Postcondition assertion: a feature that the code must have after execution

Invariant assertion: a feature that cannot change before or after code execution

Of course, in the process of using assertions, there are some things we should pay attention to and develop some good habits, such as:

1. Each assert tests only one condition, because when multiple conditions are tested at the same time, it is impossible to intuitively determine which condition failed if the assertion fails

2. Statements that change the environment cannot be used, just as the above code changed the I variable, which cannot be done in the actual process of writing code

3. Assert and the following statements should have a blank line to create logical and visual consistency

4. In some places, assert cannot replace conditional filtering

5. Check the legitimacy of incoming arguments at the entrance of function arguments

6. Assertion statements must not have any boundary effects

So many words above, seems very boring, but can't, we can't get rich quick, or want to read the text first, so that in the process of our analysis code below can quickly know why that problem again, also can be used when writing your own code to skilled assert, brings great convenience to your own code debugging, especially what are you doing in C language of the project, if you can reasonable use assert in your code, allows you to create more stable, better quality and not prone to error code. Assertions are used when you need to interrupt the current operation when a value is FALSE. Unit tests must use assertions, and in addition to type checking and unit testing, assertions provide an excellent way to determine whether various features are maintained in the program. Any good programmer can use assert in his own code and write good code.

With all that said, it's a good thing to learn about assert, but it's also a bad thing to learn about it.

The downside of using assert is that frequent calls can significantly affect program performance and add extra overhead. So after debugging, you can disable the assert call by inserting #define NDEBUG before the statement that contains #include.

Take a look at the following code:


#include <stdio.h>
//#define NDEBUG 
#include <assert.h>
int copy_string(char from[],char to[])
{
 int i=0;
 while(to[i++]=from[i]);
 printf("%sn",to);
 return 1;
}
int main()
{
 char str[]="this is a string!";
 char dec_str[206];
 printf("%sn",str); 
 assert(copy_string(str,dec_str));
 printf("%sn",dec_str);
 return 0;
}

The running result is:

< img Alt = "" border = 0 SRC =" / / files.jb51.net/file_images/article/201309/201309230908343.gif ">

In the beginning of the above code we comment out #define NDEBUG, so we enable assert, and the main function USES assert(copy_string(STR,dec_str)); To achieve copy_string function calls, we use 1 in copy_string functions return 1, so the final results of the function call is equivalent and assert (1), so continue to assert the print statements below, then the print three output statements, if we open the comments part of the beginning, the result can only be successful output start a print statements.

We've been talking about assert macros, just teaching you how to use them, so how can we implement our own assertions?

Let's look at another piece of code:


#include <stdio.h>
//#undef  _EXAM_ASSERT_TEST_    // disable 
#define  _EXAM_ASSERT_TEST_   //To enable the
#ifdef _EXAM_ASSERT_TEST_     //To enable the Assertions to test 
 void assert_report( const char * file_name, const char * function_name, unsigned int line_no )
{
 printf( "n[EXAM]Error Report file_name: %s, function_name: %s, line %un", 
         file_name, function_name, line_no );
}
 #define  ASSERT_REPORT( condition )       
 do{       
 if ( condition )       
  NULL;        
 else         
  assert_report( __FILE__, __func__, __LINE__ ); 
 }while(0)
 #else //Disable assertion test
#define ASSERT_REPORT( condition )  NULL 
#endif 
 int main( void )
{
    int i;
    i=0;
   // assert(i++);
   ASSERT_REPORT(i);
     printf("%dn",i); 
        return 0;
}

The operation results are as follows:

[EXAM]Error Report file_name: assert3.c, function_name: main, line 29
0
Careful readers will notice that we did not use an assertion to end the execution of the current program, so the printf below the assertion successfully prints the current value of I. Of course, we can also make the appropriate changes. To abort the currently executing program, modify the following:


#include <stdio.h>
#include <stdlib.h>
//#undef  _EXAM_ASSERT_TEST_    // disable 
#define  _EXAM_ASSERT_TEST_   //To enable the
#ifdef _EXAM_ASSERT_TEST_     //To enable the Assertions to test 
 void assert_report( const char * file_name, const char * function_name, unsigned int line_no )
{
 printf( "n[EXAM]Error Report file_name: %s, function_name: %s, line %un", 
         file_name, function_name, line_no );
  abort();
}
#define  ASSERT_REPORT( condition )       
 do{       
 if ( condition )       
  NULL;        
 else         
  assert_report( __FILE__, __func__, __LINE__ ); 
 }while(0)
#else //Disable assertion test
#define ASSERT_REPORT( condition )  NULL 
#endif 
 int main( void )
{
    int i;
    i=0;
   // assert(i++);
   ASSERT_REPORT(i);
    printf("%dn",i);
    return 0;
}

The operation results are as follows:

[EXAM]Error Report file_name: assert3.c, function_name: main, line 31
Aborted
The following print statement will not be executed at this point. Look at our own way, we can write your own's assertion than direct call assert macros can get more information, mainly because we write your own assert that more flexibility, can according to their own needs to print different information, but also can be used for different types of errors or warning messages of different assertions, this is also often used in the engineering code of practice. If you look at the results of the code and read my code carefully, you will see that I used a do{}while(0) in the macro definition.


#include <stdio.h>
void print_1(void)
{
 printf("print_1n");
}
void print_2(void)
{
 printf("print_2n");
}
#define  printf_value()    
   print_1();   
   print_2();   
int main( void )
{
 int i=0;
 if(i==1)
 printf_value();
 return 0;
}

Operation results:

< img Alt = "" border = 0 SRC =" / / files.jb51.net/file_images/article/201309/201309230908344.gif ">

Back up the description of the article in case the image fails to open and bothers the reader.

print_2
Press any key to continue

After looking at the above results, some readers may wonder why the above errors occurred. ! If the condition of the statement is not satisfied, then the print_value() function should not be called. If we replace the above printf_value() with print_1();   Print_2 (); , it becomes clear that the if statement only does not call print_1(); While print_2 (); In control, so the result of the above, some readers may think we add a {} is not good, here is really add a {} is ok, because this is a special case, no else, if we use {} in the macro definition above, take a look at the code after join the else statement.


#include <stdio.h>
void print_1(void)
{
 printf("print_1n");
}
void print_2(void)
{
 printf("print_2n");
}
#define  printf_value()    
  {     
  print_1();   
  print_2();}

int main( void )
{
 int i=0;
 if(i==1)
  printf_value();
 else
  printf("add else word!!!");
 return 0;
}

If the code appears to be correct, the following error appears when we compile it:

Error C2181: illegal else without matching if

Why did this go wrong? Since it is a convention to put a semicolon after each statement when we write C code, in the above code we put a semicolon after the printf_value() statement. It is because of this semicolon that there is no corresponding if for the else, the compilation fails. But if we use do{}while(0) we won't have any of these problems, so we should learn to use do{}while(0) in our macro definition as we write our code.

Assertions C content to the end, the interpretation of the above content has been given in the process of C language code detailed use assertions, including behind using our own implementation of assertion is a more classic design method of assertion, readers can in their later in the process of C language code under reference. Because oneself level is limited, the improper or the mistake in the article is inevitable, earnest hope the reader criticism correct. At the same time, readers are welcome to discuss the relevant content together. If you are willing to communicate, please leave your valuable comments.


Related articles: