How are if and else treated without brackets?

Viewed 103

Why is it that I don't see anything displayed when I run this? I was expecting EINVAL to be printed instead of nothing.

#include <stdio.h>

unsigned int set_request(int val)
{
    printf("set_request entry\n");
    return 0;
}


void main()
{
    unsigned int val = 2;

    if (val == 0 || val == 1)
        if (set_request(val))
            printf("EIO\n");
    else
        printf("EINVAL\n");
}
jj@coffy:~/nvmemaster/tmp$ ./a.out
jj@coffy:~/nvmemaster/tmp$

I am getting the right behaviour when I add {}, but I would like to know the behaviour of if without {}.

Alternatively if I modify the assignment line to 0 as shown below, then I am seeing something else odd. Now I wasn't expecting EINVAL to be printed.

#include <stdio.h>

unsigned int set_request(int val)
{
    printf("set_request entry\n");
    return 0;
}


void main()
{
    unsigned int val = 0;

    if (val == 0 || val == 1)
        if (set_request(val))
            printf("EIO\n");
    else
        printf("EINVAL\n");
}
jj@coffy:~/nvmemaster/tmp$ gcc if.c
jj@coffy:~/nvmemaster/tmp$ ./a.out
set_request entry
EINVAL
jj@coffy:~/nvmemaster/tmp$
3 Answers

An else will bind to the innermost if. So this:

if (val == 0 || val == 1)
    if (set_request(val))
        printf("EIO\n");
else
    printf("EINVAL\n");

Is actually the same as:

if (val == 0 || val == 1) {
    if (set_request(val)) {
        printf("EIO\n");
    } else {
        printf("EINVAL\n");
    }
}

The braces are needed to correctly bind the else clause. For this reason, it's best to always use them with if...else to avoid confusion.

Your code looks like this

    if (val == 0 || val == 1)
        if (set_request(val))
            printf("EIO\n");
    else
        printf("EINVAL\n");

Now indentation doesn't matter to the compiler, so it puts braces like this

    if (val == 0 || val == 1)
    {
       if (set_request(val))
            printf("EIO\n");
       else
            printf("EINVAL\n");
    }

So the else is not matched with the first if, but the second one.

It appears that you actually want something like

    if (val == 0 || val == 1)
    {
       if (set_request(val))
            printf("EIO\n");
    }
    else
       printf("EINVAL\n");

In which case you need to specify the braces. Note that to avoid this kind of ambiguity, it's best to always be explicit with braces.

Also, if you compile with warnings turned on, the compiler will warn about your code snippet. [-Wdangling-else]

The else is matched to the closest preceding if statement. This situation has a name, it's the dangling else problem. Your code is actually seen by the compiler as:

void main()
{
    unsigned int val = 0;

    if (val == 0 || val == 1)
        if (set_request(val))
            printf("EIO\n");
        else
            printf("EINVAL\n");
}

That's why you must use curly braces to make your intention clear. If you want the else bound to the outer if you could write your code as:

void main()
{
    unsigned int val = 0;

    if (val == 0 || val == 1) {
        if (set_request(val))
            printf("EIO\n");
    } else
        printf("EINVAL\n");
}
Related