...
In particular, do not default the test for non-zero. For instance, suppose a foo()
function returns 0 to indicate failure, or a non-zero value to indicate success. Testing for inequality with zero:
Code Block | ||
---|---|---|
| ||
if (foo() != 0) ... |
is preferable to
Code Block | ||
---|---|---|
| ||
if (foo()) ... |
despite the convention that 0 indicates failure. Explicitly testing for inequality with zero benefits maintainability if foo()
is later modified to return -1 rather than 0 on failure.
...
Code Block | ||
---|---|---|
| ||
LinkedList bannedUsers; int is_banned(User usr) { int x = 0; Node cur_node = (bannedUsers->head); while (cur_node != NULL) { if(strcmp((char *)cur_node->data, usr->name) { x++; } cur_node = cur_node->next; } return x; } void processRequest(User usr) { if(is_banned(usr) == 1) { return; } serveResults(); } |
...
If a banned user is listed twice, the user is granted access. Although is_banned()
follows the common convention of returning non-zero for true, processRequest
only checks for equality with 1.
...
Because most functions only guarantee a return value of non-zero for true, the above code above is better written by checking for inequality with 0 (false) as follows.:
Code Block | ||
---|---|---|
| ||
LinkedList bannedUsers; int is_banned(User usr) { int x = 0; Node cur_node = (bannedUsers->head); while(cur_node != NULL) { if (strcmp((char *)cur_node->data, usr->name) { x++; } cur_node = cur_node->next; } return x; } void processRequest(User usr) { if (is_banned(usr) != 0) { return; } serveResults(); } |
Noncompliant Code Example
In this noncompliant code example, function failures Function status can typically be indicated by one of the following return values: returning -1
on failure, a non-zero numberor any nonnegative number on success. While this is a common convention in the standard C library, it is discouraged in ERR02-C. Avoid in-band error indicators.
Although failures are frequently indicated by a return value of zero, there are common conventions that may conflict in the future with code where the test for non-zero is not explicit. 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 also common conventions).
Code Block | ||
---|---|---|
| ||
int validateUser(User usr) {
if(listContains(validUsers, usr)) {
return 1;
}
return 0;
}
void processRequest(User usr, Request request) {
if(!validateUser(usr)) {
return "invalid user";
}
else {
serveResults();
}
}
|
The Although the code above will work as intended. However, it is very feasible possible that a future modification will result in the following.:
Code Block | ||
---|---|---|
| ||
errno_t validateUser(User usr) { if(list_contains(allUsers, usr) == 0) { return 303; // user not found error code } if(list_contains(validUsers, usr) == 0) { return 304; // invalid user error code } return 0; } void processRequest(User usr, Request request) { if(!validateUser(usr)) { return "invalid user"; } serveResults(); } |
...
The code above works correctly. However, in order to simplify the login code or to facilitate checking a user's password more than once, a programmer might separate the password checking code from the login function. they might do so in the following way.
...