Do not default the test for non-zero. Performing explicit tests to determine success, true/false, and equality makes code both maintainable and compliant with common conventions.
This recommendation is derived from and considers the implications of the following common conventions:
(1) Function failures are typically indicated by one of the following return values: 0, -1, an error number.
(2) Functions return 0 if false, but only non-zero if true.
(3) Comparison functions (such as the standard library function strcmp()) return 0 if the arguments are equal and non-zero otherwise.
Noncompliant Code Example
In regards to (1):
Although failures are frequently indicated by a return value of zero (which C considers to be false), there are common conventions that may conflict in the future with code where the test for non-zero is not explicit.
Basically,
#define FAIL 0
if(foo()==FAIL)
is preferable for code maintenance to
if(foo())
In this case, defaulting the test for non-zero welcomes bugs if and when a developer modifies foo to return an error code or -1 rather than 0 to indicate a failure (all of which are common conventions).
Code Block | ||
---|---|---|
| ||
if(foo())
{
return 0;
}
|
Compliant Solution
The following is preferable for code maintenance. By defining what constitutes a failure and explicitly testing for it, the behavior is clearly implied and future modifications are more likely to preserve it.
Code Block | ||
---|---|---|
| ||
\#define FAIL 0
if(foo()==FAIL) // explicit test for failure
{
return 0;
}
|
Noncompliant Code Example
In regards to (2):
Though rare, the The following is fairly common :
#define TRUE 1
yet ignores the convention that most functions in C only guarantee a non-zero return value to indicate True/Yes/etc..
Code Block | ||
---|---|---|
| ||
\#define TRUE 1 if(foo() == TRUE) // Will evaluate to False if foo() returns 2, though that may logically imply a result of True. { return true; } |
Compliant Solution
Because However, because most functions only guarantee a return value of non-zero for "true," the code above is better written by checking for inequality with 0 ("false") as follows.
Code Block | ||
---|---|---|
| ||
\#define FALSE 0 |
...
if(foo() \!= FALSE) // Given convention (2), this will always yield the intended behavior. { return true; } |
In regards to (3):
Because comparison functions (like strcmp) return 0 for equality and non-zero for inequality, they can cause confusion when used to test for equality. If someone were to switch the following strcmp call with an equals function, they might instinctively just replace the function name.
...