The little secrets of C language-Assertions

Source: Internet
Author: User
Tags prototype definition

Every time I write a summary, I think it is a headache, because I know that the summary is really important, and it almost directly determines the number of readers. It may take a lot of effort to write things, because the failure of the abstract has all the work left, because most readers will browse the abstract before reading the article. If they find that the abstract is "not matching ", there is no special or attractive place, so we will use a ten-Row Method to read the full text, and I will sentence the article to the "death penalty". Although the quality of an article cannot be measured by a summary, however, it is often used by readers to measure the quality of an article, thus becoming a key factor in the number of readers. The following is a back-to-back story about assertions. If I study C language in general and take the test, I think few people will use assertions in the Code. Maybe some people have never used assertions before. So what can the use of assertions bring to our code? I try my best to explain the usage of the assertions I understand clearly. I hope the assertions I mentioned here will help you and allow you to use them flexibly in the code in the future.

Before proceeding, let's give a basic introduction to assertions to give you a general understanding of assertions. When writing Engineering Code in C language, we always check certain assumptions. assertions are used to capture these assumptions in the Code and can be seen as an advanced form of exception processing. Assertions are expressed as boolean expressions. The programmer believes that the expression value is true at a specific point in the program. You can enable and disable Assertion Verification at any time, so you can enable assertion during testing and disable assertion during deployment. Similarly, after the program is put into operation, the end user can re-use the assertions in case of problems. It can quickly detect and locate software problems and automatically trigger alarms for system errors. Assertions can be hidden deeply in the system, and can be used to locate problems that are extremely difficult to find by other means. This can shorten the time for locating software problems and improve the testability of the system. In actual applications, You can flexibly design Assertions based on specific situations.

Through the above explanation, we have a rough understanding of assertions, so let's take a look at the use of the assert macro in the C language in the code.

Prototype definition:

Void assert (INT expression );

The assert macro prototype is defined in <assert. h>. The function is to calculate the expression first. If the expression value is false (that is, 0), It prints an error message to stderr first, then, terminate the program by calling abort.

Let's take a look at a piece of code:

# Include <stdio. h>
# Include <assert. h>

Int main (void)
{
Int I;
I = 1;
Assert (I ++ );

Printf ("% d \ n", I );

Return 0;
}

The running result is:

Let's look at the running result. Because the initial I value is 1, we use assert (I ++); the error will not occur when the statement is executed, and then I ++ is executed, therefore, the output value of the subsequent print statement is 2. If we change the initial value of I to 0, the following error is returned.
Assertion failed: I ++, file E: \ fdsa \ assert2.cpp, line 8
Press any key to continue

Did you find that you can quickly locate the error point as prompted ?! Since assert is so easy to locate the error point, it seems that we really need to be skilled in using it in the code, but there are rules for the use of anything, and the use of assert is no exception.

The assert statement is not always executed, can be blocked or enabled, which requires that assert cannot affect the function of our code, whether it is blocked or enabled, in this case, we just used an Assert (I ++) in the Code. This is not appropriate, because once we disable assert, the I ++ statement will not be executed, the use of the next I value will cause problems, so we should implement such a statement separately and write the following two sentences to replace assert (I ); I ++;, so this requires the use of assertions. Under what circumstances do we usually use assertions? Mainly reflected in the following aspects:

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

2. Pre-and Post-Conditions for executing the test method using assertions.

3. Use assertions to check the unchanged state of the class to ensure that the state of a variable must be met under any circumstances. (For example, the change range of a variable)

If you are not familiar with the preceding preconditions and preconditions, you will understand the following explanation.

Preconditions assertions: features required before Code Execution

Post-condition assertions: features required after Code Execution

Unchanged assertion: Non-changeable features before and after Code Execution

Of course, there will be some precautions and good habits in the process of using assertions, such:

1. Each assert tests only one condition, because when multiple conditions are verified simultaneously, if the assert fails, we cannot intuitively determine which condition fails.

2. You cannot use statements that change the environment. Just as the code above changes the I variable, you cannot do this in the actual code writing process.

3. assert and the following statement should be empty in order to form a sense of logical and visual consistency. It is also a good programming habit, so that the written code has a visual aesthetic.

4. In some cases, assert cannot replace conditional filtering.

5. Check the validity of the input parameter at the entrance of the function parameter.

6. assertion statements cannot have any boundary effect

The above text seems boring, but there is no way. We can't rush for immediate success or profit, but we should insist on reading the text description first, in this way, we can quickly find out why such a problem occurs in the following code analysis process and use assert skillfully when writing the code, it brings great convenience to code debugging. Especially when you use C language for engineering projects, if you can reasonably use assert in your code, it allows you to create code with higher stability, quality, and difficulty in making mistakes. You can use assertions to interrupt the current operation when the value is false. Unit tests must use assertions. In addition to type checks and unit tests, assertions also provide an excellent way to determine whether various features are maintained in the program. All excellent programmers can use assert in their own code to Compile High-Quality code.

When talking about so many assert operations, we should also talk about its shortcomings.

The disadvantage of using assert is that frequent calls will greatly affect program performance and increase additional overhead. Therefore, after debugging, you can disable assert calling by inserting # define ndebug before the # include statement.

Next, we will analyze the code below:

# Include <stdio. h>
// # Define ndebug
# Include <assert. h>

Int copy_string (char from [], Char to [])
{
Int I = 0;
While (to [I ++] = from [I]);

Printf ("% s \ n", );

Return 1;
}

Int main ()
{
Char STR [] = "this is a string! ";
Char dec_str [206];

Printf ("% s \ n", STR );

Assert (copy_string (STR, dec_str ));

Printf ("% s \ n", dec_str );

Return 0;
}

The running result is:

At the beginning of the above Code, we commented out # define ndebug, So we enabled assert. The main function uses assert (copy_string (STR, dec_str )); to call the copy_string function. In the copy_string function, we use return 1, so the final function call result is equivalent to assert (1 ), so next we will continue to execute the print statement below assert, and finally successfully print three output statements. If we open the comments at the beginning, the result will only be able to output one print statement at the beginning.

The above is all about the assert macro. It only teaches you how to use the assert Macro. Then let's take a look at how we can implement our own assertions?

Next let's look at another piece of code:

# Include <stdio. h>

// # UNDEF _ exam_assert_test _ // disable
# DEFINE _ exam_assert_test _ // enable
# Ifdef _ exam_assert_test _ // enable assertion 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 % u \ n ",
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/* end of assert */
Int main (void)
{
Int I;
I = 0;
// Assert (I ++ );
Assert_report (I );
Printf ("% d \ n", I );
Return 0;
}

The running result is as follows:

[Exam] Error Report file_name: assert3.c, function_name: Main, Line 29
0
Careful readers will find that we have not used assertions to end the execution of the current program, so the printf under the assertions successfully prints the current value of I, of course, we can also make appropriate modifications. If an error occurs during the assertion, we can call abort () to terminate the program that is currently being executed. The modifications are as follows:

# Include <stdio. h>
# Include <stdlib. h>

// # UNDEF _ exam_assert_test _ // disable
# DEFINE _ exam_assert_test _ // enable
# Ifdef _ exam_assert_test _ // enable assertion 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 % u \ n ",
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/* end of assert */
Int main (void)
{
Int I;
I = 0;
// Assert (I ++ );
Assert_report (I );
Printf ("% d \ n", I );
Return 0;

}

The running result is as follows:

[Exam] Error Report file_name: assert3.c, function_name: Main, line 31
Aborted
At this time, the following print statement will not be executed. By looking at our own implementation methods, we know that the assertions we write can get more information than calling the assert macro directly, mainly because the assertions we write are more flexible, different types of errors or warnings can be printed and output as needed. Different assertions are also often used in engineering code. If you read my code carefully while paying attention to the code running results, you will find that I used a do {} while (0) in the macro definition ), what are the advantages of using it? It may not be reflected in the above Code. Let's look at the following code and you will know.

# Include <stdio. h>

Void print_1 (void)
{
Printf ("print_1 \ n ");
}
Void print_2 (void)
{
Printf ("print_2 \ n ");
}
# Define printf_value ()\
Print_1 ();\
Print_2 ();\

Int main (void)
{
Int I = 0;
If (I = 1)
Printf_value ();

Return 0;
}

Running result:

Back up the article description to prevent readers from being troubled by image opening failure.

Print_2
Press any key to continue

After reading the above running results, some readers may wonder why the above errors have occurred ?! If statement conditions are not met, the print_value () function should not be called. How can it be printed. If we replace the above printf_value () with print_1 (); print_2 ();, we will clearly find that the if statement serves not only to call print_1 ();, print_2 (); in addition to control, some readers may immediately think that it is better to add, you can add {} here, because it is a special case that there is no else statement. If we use {} in the macro definition above {}, add the else statement and check the code again.

# Include <stdio. h>

Void print_1 (void)
{
Printf ("print_1 \ n ");
}

Void print_2 (void)
{
Printf ("print_2 \ n ");
}

# 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 occurs during compilation:

Error c2181: Illegal else without matching if

Why is such an error? When we write C language code, adding a plus sign after each statement is a convention. In the above Code, we add a semicolon after the printf_value () statement, it is precisely because of the role of this semicolon that else has no corresponding if, so compilation error. However, if we use do {} while (0), these problems will not occur, so we should learn to use do {} while (0) in macro definition when writing code ).

This is the end of the explanation of the C language assertions. The above content has provided the detailed use of assertions during the C language coding process, the assertions we implement later are considered to be a classic design method for assertions. You can refer to them when writing C language code. Due to my limited level, improper or incorrect content in my blog is inevitable, and I hope readers will criticize and correct me. Readers are also welcome to discuss relevant content. If you are willing to share your comments, please leave your valuable comments.

Every time I write a summary, I think it is a headache, because I know that the summary is really important, and it almost directly determines the number of readers. It may take a lot of effort to write things, because the failure of the abstract has all the work left, because most readers will browse the abstract before reading the article. If they find that the abstract is "not matching ", there is no special or attractive place, so we will use a ten-Row Method to read the full text, and I will sentence the article to the "death penalty". Although the quality of an article cannot be measured by a summary, however, it is often used by readers to measure the quality of an article, thus becoming a key factor in the number of readers. The following is a back-to-back story about assertions. If I study C language in general and take the test, I think few people will use assertions in the Code. Maybe some people have never used assertions before. So what can the use of assertions bring to our code? I try my best to explain the usage of the assertions I understand clearly. I hope the assertions I mentioned here will help you and allow you to use them flexibly in the code in the future.

Before proceeding, let's give a basic introduction to assertions to give you a general understanding of assertions. When writing Engineering Code in C language, we always check certain assumptions. assertions are used to capture these assumptions in the Code and can be seen as an advanced form of exception processing. Assertions are expressed as boolean expressions. The programmer believes that the expression value is true at a specific point in the program. You can enable and disable Assertion Verification at any time, so you can enable assertion during testing and disable assertion during deployment. Similarly, after the program is put into operation, the end user can re-use the assertions in case of problems. It can quickly detect and locate software problems and automatically trigger alarms for system errors. Assertions can be hidden deeply in the system, and can be used to locate problems that are extremely difficult to find by other means. This can shorten the time for locating software problems and improve the testability of the system. In actual applications, You can flexibly design Assertions based on specific situations.

Through the above explanation, we have a rough understanding of assertions, so let's take a look at the use of the assert macro in the C language in the code.

Prototype definition:

Void assert (INT expression );

The assert macro prototype is defined in <assert. h>. The function is to calculate the expression first. If the expression value is false (that is, 0), It prints an error message to stderr first, then, terminate the program by calling abort.

Let's take a look at a piece of code:

# Include <stdio. h>
# Include <assert. h>

Int main (void)
{
Int I;
I = 1;
Assert (I ++ );

Printf ("% d \ n", I );

Return 0;
}

The running result is:

Let's look at the running result. Because the initial I value is 1, we use assert (I ++); the error will not occur when the statement is executed, and then I ++ is executed, therefore, the output value of the subsequent print statement is 2. If we change the initial value of I to 0, the following error is returned.
Assertion failed: I ++, file E: \ fdsa \ assert2.cpp, line 8
Press any key to continue

Did you find that you can quickly locate the error point as prompted ?! Since assert is so easy to locate the error point, it seems that we really need to be skilled in using it in the code, but there are rules for the use of anything, and the use of assert is no exception.

The assert statement is not always executed, can be blocked or enabled, which requires that assert cannot affect the function of our code, whether it is blocked or enabled, in this case, we just used an Assert (I ++) in the Code. This is not appropriate, because once we disable assert, the I ++ statement will not be executed, the use of the next I value will cause problems, so we should implement such a statement separately and write the following two sentences to replace assert (I ); I ++;, so this requires the use of assertions. Under what circumstances do we usually use assertions? Mainly reflected in the following aspects:

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

2. Pre-and Post-Conditions for executing the test method using assertions.

3. Use assertions to check the unchanged state of the class to ensure that the state of a variable must be met under any circumstances. (For example, the change range of a variable)

If you are not familiar with the preceding preconditions and preconditions, you will understand the following explanation.

Preconditions assertions: features required before Code Execution

Post-condition assertions: features required after Code Execution

Unchanged assertion: Non-changeable features before and after Code Execution

Of course, there will be some precautions and good habits in the process of using assertions, such:

1. Each assert tests only one condition, because when multiple conditions are verified simultaneously, if the assert fails, we cannot intuitively determine which condition fails.

2. You cannot use statements that change the environment. Just as the code above changes the I variable, you cannot do this in the actual code writing process.

3. assert and the following statement should be empty in order to form a sense of logical and visual consistency. It is also a good programming habit, so that the written code has a visual aesthetic.

4. In some cases, assert cannot replace conditional filtering.

5. Check the validity of the input parameter at the entrance of the function parameter.

6. assertion statements cannot have any boundary effect

The above text seems boring, but there is no way. We can't rush for immediate success or profit, but we should insist on reading the text description first, in this way, we can quickly find out why such a problem occurs in the following code analysis process and use assert skillfully when writing the code, it brings great convenience to code debugging. Especially when you use C language for engineering projects, if you can reasonably use assert in your code, it allows you to create code with higher stability, quality, and difficulty in making mistakes. You can use assertions to interrupt the current operation when the value is false. Unit tests must use assertions. In addition to type checks and unit tests, assertions also provide an excellent way to determine whether various features are maintained in the program. All excellent programmers can use assert in their own code to Compile High-Quality code.

When talking about so many assert operations, we should also talk about its shortcomings.

The disadvantage of using assert is that frequent calls will greatly affect program performance and increase additional overhead. Therefore, after debugging, you can disable assert calling by inserting # define ndebug before the # include statement.

Next, we will analyze the code below:

# Include <stdio. h>
// # Define ndebug
# Include <assert. h>

Int copy_string (char from [], Char to [])
{
Int I = 0;
While (to [I ++] = from [I]);

Printf ("% s \ n", );

Return 1;
}

Int main ()
{
Char STR [] = "this is a string! ";
Char dec_str [206];

Printf ("% s \ n", STR );

Assert (copy_string (STR, dec_str ));

Printf ("% s \ n", dec_str );

Return 0;
}

The running result is:

At the beginning of the above Code, we commented out # define ndebug, So we enabled assert. The main function uses assert (copy_string (STR, dec_str )); to call the copy_string function. In the copy_string function, we use return 1, so the final function call result is equivalent to assert (1 ), so next we will continue to execute the print statement below assert, and finally successfully print three output statements. If we open the comments at the beginning, the result will only be able to output one print statement at the beginning.

The above is all about the assert macro. It only teaches you how to use the assert Macro. Then let's take a look at how we can implement our own assertions?

Next let's look at another piece of code:

# Include <stdio. h>

// # UNDEF _ exam_assert_test _ // disable
# DEFINE _ exam_assert_test _ // enable
# Ifdef _ exam_assert_test _ // enable assertion 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 % u \ n ",
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/* end of assert */
Int main (void)
{
Int I;
I = 0;
// Assert (I ++ );
Assert_report (I );
Printf ("% d \ n", I );
Return 0;
}

The running result is as follows:

[Exam] Error Report file_name: assert3.c, function_name: Main, Line 29
0
Careful readers will find that we have not used assertions to end the execution of the current program, so the printf under the assertions successfully prints the current value of I, of course, we can also make appropriate modifications. If an error occurs during the assertion, we can call abort () to terminate the program that is currently being executed. The modifications are as follows:

# Include <stdio. h>
# Include <stdlib. h>

// # UNDEF _ exam_assert_test _ // disable
# DEFINE _ exam_assert_test _ // enable
# Ifdef _ exam_assert_test _ // enable assertion 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 % u \ n ",
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/* end of assert */
Int main (void)
{
Int I;
I = 0;
// Assert (I ++ );
Assert_report (I );
Printf ("% d \ n", I );
Return 0;

}

The running result is as follows:

[Exam] Error Report file_name: assert3.c, function_name: Main, line 31
Aborted
At this time, the following print statement will not be executed. By looking at our own implementation methods, we know that the assertions we write can get more information than calling the assert macro directly, mainly because the assertions we write are more flexible, different types of errors or warnings can be printed and output as needed. Different assertions are also often used in engineering code. If you read my code carefully while paying attention to the code running results, you will find that I used a do {} while (0) in the macro definition ), what are the advantages of using it? It may not be reflected in the above Code. Let's look at the following code and you will know.

# Include <stdio. h>

Void print_1 (void)
{
Printf ("print_1 \ n ");
}
Void print_2 (void)
{
Printf ("print_2 \ n ");
}
# Define printf_value ()\
Print_1 ();\
Print_2 ();\

Int main (void)
{
Int I = 0;
If (I = 1)
Printf_value ();

Return 0;
}

Running result:

Back up the article description to prevent readers from being troubled by image opening failure.

Print_2
Press any key to continue

After reading the above running results, some readers may wonder why the above errors have occurred ?! If statement conditions are not met, the print_value () function should not be called. How can it be printed. If we replace the above printf_value () with print_1 (); print_2 ();, we will clearly find that the if statement serves not only to call print_1 ();, print_2 (); in addition to control, some readers may immediately think that it is better to add, you can add {} here, because it is a special case that there is no else statement. If we use {} in the macro definition above {}, add the else statement and check the code again.

# Include <stdio. h>

Void print_1 (void)
{
Printf ("print_1 \ n ");
}

Void print_2 (void)
{
Printf ("print_2 \ n ");
}

# 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 occurs during compilation:

Error c2181: Illegal else without matching if

Why is such an error? When we write C language code, adding a plus sign after each statement is a convention. In the above Code, we add a semicolon after the printf_value () statement, it is precisely because of the role of this semicolon that else has no corresponding if, so compilation error. However, if we use do {} while (0), these problems will not occur, so we should learn to use do {} while (0) in macro definition when writing code ).

This is the end of the explanation of the C language assertions. The above content has provided the detailed use of assertions during the C language coding process, the assertions we implement later are considered to be a classic design method for assertions. You can refer to them when writing C language code. Due to my limited level, improper or incorrect content in my blog is inevitable, and I hope readers will criticize and correct me. Readers are also welcome to discuss relevant content. If you are willing to share your comments, please leave your valuable comments.

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.