Uses assert () for production not approved by if..else .. blocks?

I find that using assert(...) makes my code shorter and easier to read, unlike long if..else.. blocks. However, are there any good technical reasons not to use assert(...) in transport code when it does the same thing as testing the return value when using smaller code?

+7
source share
9 answers

After reading this article , I will share my beliefs about assert :

  • Yes, itโ€™s good to use assert when something absolutely must meet the condition you are claiming.

  • Many languages โ€‹โ€‹allow you to raise user errors, if you say that C does not have an โ€œExceptionโ€, it can lead to errors that are a bit more difficult to diagnose without directly looking at the source in question.

+4
source

If this is a programming error (possibly causing), use assert .

If this is not a programming error, use if / else and handle the situation accordingly.

+4
source

Approves well. Compile-time statements are even better. Remarks:

If your environment does not yet have a static statement, here is a suggestion.

The ASSERT() macro below can be placed anywhere in the code except:

  • In a double-included header file without the #ifndef...#endif shell.
  • In the middle of a structure definition (or enum definition).
  • In strict C89 or C90, after declaration. (But you can wrap it in braces!)

If you want to insert something in the middle of the structure definition, you need to use the long, ugly #if...#error...#endif construct #if...#error...#endif . And if you do this, the preprocessor will have a much more limited idea of โ€‹โ€‹what a "constant expression" is.

This is a refinement of ideas from the Internet, mainly from http://www.pixelbeat.org/programming/gcc/static_assert.html . This definition is shorter than BOOST_STATIC_ASSERT() . And, I suppose, better than Linus's suggestion for improved BUILD_BUG_ON() . And the do{...}while(0) shell you usually see is completely inapplicable here, since it limits the permissible locations.

It is also simpler than Google COMPILE_ASSERT / CompileAssert. The "sizeof bitfield" trick also seems good, from Linux BUILD_BUG_ON_ZERO() , but not from its useless brother BUILD_BUG_ON() .

There are many suggestions for using negative index arrays. But with GCC, most of them do not detect an inconsistent arg argument (which is quite easy to do by mistake), with the exception of extern int foo [expression], which also issues a warning "unused variable". But typedef int array[expression] also looks good: see below.

Definition:

 #define CONCAT_TOKENS(a, b) a ## b #define EXPAND_THEN_CONCAT(a,b) CONCAT_TOKENS(a, b) #define ASSERT(e) enum{EXPAND_THEN_CONCAT(ASSERT_line_,__LINE__) = 1/!!(e)} 

Equally good, I suppose the following option, but it is five characters longer:

 #define ASSERT(e) typedef int EXPAND_THEN_CONCAT(ASSERT_line_,__LINE__)[1-2*!(e)] 

There is also a do{switch(0){case 0:case(e):;}}while(0) construct that I have not explored.

Sometimes you need an option to handle the case when two different header files randomly have two ASSERT () on the same line or the same for the source file and header file. You could handle this via __COUNTER__ , but this is not supported by some compilers (and this is uglier). And we cannot use __FILE__ because it usually does not expand to a valid C token (for example, it has point c or point h). Mozilla's version of http://mxr.mozilla.org/mozilla-central/source/mfbt/Assertions.h states that such conflicts "should be rare," but they will greatly annoy your teammates when this happens. It can also be used to handle multiple ASSERTS in a multi-line macro, where __LINE__ does not change.

 #define ASSERTM(e,m) enum{EXPAND_THEN_CONCAT(m##_ASSERT_line_,__LINE__)=1/!!(e)} 

The next option, ASSERT_zero(), is similar to BUILD_BUG_ON_ZERO(), using the "sizeof bitfield" trick. This gives either:

  • compilation error when e false, or
  • the value is zero.

Therefore, it can be used in places where the operator cannot, for example, in the middle of an expression.

 #ifndef __cplusplus #define ASSERT_zero(e) (!sizeof(struct{int:!!(e);})) // cf. BUILD_BUG_ON_ZERO(), !C++ #else #define ASSERT_zero(e) (!sizeof(char[(e) ? 1 : -1])) // careful: g++ has VLAs #endif 
+3
source

IMO, none of the answers here speaks of the most important part: Statements affirm the assumptions of programmers. assert(x) says something like "x is always true at the moment, you can check it if you want." If the user ever sees an approval error, it means that you did something wrong.

You probably need a function that will do almost the same thing as assert, but also in release and debug modes. Using check(x) means "Check that x is true. If it is not, tell the user and close"

+3
source

assert() is for things that should never be false under normal conditions.

if - else is for things that can sometimes be false under normal conditions, because the else part is designed to handle such situations gracefully.

In short, if are designed to prevent failures; assert() intended to create them.

+2
source

While the other answers contain some good information, it doesn't seem to me that I directly addressed the question you asked.

IMO, yes, there is a pretty significant drawback to leaving assert in the (most) production code: you don't get control over the error message, which often looks pretty scary.

Instead of something like:

 Fatal error: Assertion failed! x != NULL in xxx.c, line 107 

I would rather give the client something like:

 Please contact customer support and give them code xxx:107 
+2
source

I think using assert for runtime errors is bad, especially because it is against the convention:

  • assert usually compiled from non-debug collections. Now you can compile all your builds with the expectation that assert always on, but anyone who inherits your code later may not understand this. It will be even worse if you write code where your assert have side effects (for example, assert((fp = fopen(filename, "r")) != NULL) ).

  • Similarly, assert intended to be used for logical errors, not runtime errors. When you start using assert to check for runtime errors, you start to distort how your code should behave for anyone trying to read it. The maintainers will not be able to easily distinguish between logical errors and possible runtime errors, and the difference is useful in discussing the behavior of the code.

And do you really want your program to abruptly stop working and dump the kernel if the user accidentally leaves the input field empty? This is incredibly hostile user.

If you think using assert less than code, you can try writing your own separate macro. This will avoid changing the expected semantics of assert and hostility. For example, something like:

 #define FAIL_IF(cond, action) do { if (cond) { action; } } while (0) FAIL_IF((fp = fopen(filename, "r")) == NULL, goto exit); 
+2
source

I do not share the point of view of those who say that this is true. As soon as I screwed up, the Qt statements were defined as follows:

 #ifdef DEBUG # define q_assert(...) ... #endif 

and I wrote something like

 q_assert(some_ptr_type a = get_new_ptr()); 

When I executed it in release mode, I was puzzled by a never initialized one.

+1
source

Like java exceptions, assert gives fault tolerance. This is a very good practice to significantly increase time and effort. But the delivery code should have quick releases as a web application, and not something like a CD distribution. In addition, in java, exceptions can be caught, logged and presented well.

0
source

All Articles