Introduction
One of the bad things that the C language allows is setting
variables and calling functions directly in an if
statement.
This should be avoided due to how the statement can exit early
stopping some of the logic from happening.
That said, this can also be abused to write more compact code. Not that you should do this because it’s better to have maintainable, rather than clever code.
While how if
statements evaluate segments to most programmers.
It’s isn’t necessarily obvious to novice ones. An OR (||
) compound
will exit evaluation early if the first part of the evaluation
is true
.
The if
Statement
if
statements are evaluated left to right and stop as soon
as all conditions are met. Meaning, any code after the conditions
are met will not be run. This is a very bad pattern.
Example 1: Function Return
Let’s start with two simple functions to demonstrate.
static bool func_f(void)
{
printf("False\n");
return false;
}
static bool func_t(void)
{
printf("True\n");
return true;
}
First let’s evaluate with func_f
first.
if (func_f() || func_t())
;
We’ll end up with the output:
False
True
However, if we flip the order.
if (func_t() || func_f())
;
We end up with only func_t
running:
True
In this case, due to all conditions being stratified
once func_t
ran, func_f
is never called.
You could use pattern instead of putting func_f
in
the body of the if
statement.
if (!func_t())
func_f();
Example 2: Setting values
Now let’s look at setting a variable within the if statement.
size_t a = 0;
size_t b = 2;
Take this where we call a function that returns true
but then
evaluates a variable that is being assigned a value.
if (func_t() || (a = 3))
;
printf("a = %zu\n", a);
In this case we end up with:
True
a = 0
Once again, since the if
statement ends once func_t
returns
true
, a
is never set to 3.
The same early exit happens with this as well:
if ((a = 4) || (b = 7))
;
printf("a = %zu, b = %zu\n", a, b);
Where we get:
a = 4, b = 2
Example 3: Setting values passed to functions
When calling a function and setting with an assignment
as a parameter, the assignment happens before the
function is called. However, the if
statement
early exit still takes place and it takes place
before the assignment of the second part that is, itself,
a parameter to a function.
First we need another function.
static bool func_v(size_t v)
{
printf("v = %zu\n", v);
return true;
}
This time we’ll use an AND (&&
) compound to show
the variables are set before the function call
if (func_v(a = 9) && func_v(b = 8))
;
printf("a = %zu, b = %zu\n", a, b);
And we get this output:
v = 9
v = 8
a = 9, b = 8
Now let’s use an OR.
if (func_v(a = 15) || func_v(b = 15))
;
printf("a = %zu, b = %zu\n", a, b);
Once again, only the first part of the evaluation takes place.
And since the second part does not, not only is func_v
not
called a second time, b
’s value is not changed.
v = 15
a = 15, b = 8
Conclusion
This should all seem obvious to an experienced programmer but can cause major issues when a novice (or even veteran) tries to be clever. Don’t follow this pattern with C. A pattern similar to this is often used in Lua but this is a case where patterns don’t always translate from one language to another.