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.