Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there objective reason against using braces even where not necessary?

Tags:

c

Both kernel coding style and gnome's C style guide states that:

Do not unnecessarily use braces where a single statement will do.

if (condition)
        action();

but at the same time it should be sometimes used, as in else branch of:

if (condition) {
        do_this();
        do_that();
} else {
        otherwise();
}

Is there any technical or usability reasons to prefer it this way? Are there any objective reasons not to put the braces there everytime?

like image 958
graywolf Avatar asked Mar 20 '20 17:03

graywolf


2 Answers

There are only stylistic and ease-of-editing-related reasons.

Whether you omit the brace or not, C compilers must act as if the braces were there (+ a pair around the whole iteration statement (if or if-else)).

6.8.4p3:

A selection statement is a block whose scope is a strict subset of the scope of its enclosing block. Each associated substatement is also a block whose scope is a strict subset of the scope of the selection statement.

The existence of these implicit blocks can be nicely demonstrated with enums:

#include <stdio.h>
int main()
{
    enum{ e=0};
    printf("%d\n", (int)e);
    if(1) printf("%d\n", (sizeof(enum{e=1}),(int)e));
    if(sizeof(enum{e=2})) printf("%d\n", (int)e);
    printf("%d\n", (int)e);

    //prints 0 1 2 0
}

A similar rule also exists for iteration statements: 6.8.5p5.

These implicit blocks also mean that a compound literal defined inside an iteration or selection statement is limited to such an implicit block. That is why example http://port70.net/~nsz/c/c11/n1570.html#6.5.2.5p15 from the standard puts a compound literal in between a label an explicit goto instead of simply using a while statement, which would limit the scope of the literal, regardless of whether or not explicit braces were used.

While it may be tempting, don't ever do:

if (Ptr) Ptr = &(type){0}; //WRONG way to provide a default for Ptr

The above leads to UB (and actually nonworking wit gcc -O3) because of the scoping rules.

The correct way to do the above is either with:

type default_val = {0};
if (Ptr) Ptr = &default_val; //OK

or with:

Ptr = Ptr ? Ptr : &(type){0}; //OK

These implicit blocks are new in C99 and the inner ones (for selection statements (=ifs)) are well rationalized (C99RationaleV5.10.pdf, section 6.8) as aids in refactoring, preventing braces that are added from previously unbraced branches from changing meaning.

The outermost branch around the whole selection statements doesn't appear to be so well rationalized, unfortunately (more accurately, it's not rationalized at all). It appears copied from the rule for iterations statements, which appears to copy the C++ rules where for-loop-local variables are destructed at the very end of the whole for loop (as if the for loop were braced).

(Unfortunately, I think that for selection statement the outermost implicit {} does more harm than good as it prevents you from having macros that stack-allocate in just the scope of the caller but also need a check, because then you can only check such macros with ?: but not with if, which is weird.)

like image 148
PSkocik Avatar answered Sep 27 '22 20:09

PSkocik


Well, there's one special case in which braces do need to be used: Suppose you have the following code:

if (a)
    if (b)
        f();
else g();

As it is indented, one could assume the else g(); statement belongs to the first if(a) statement, but C syntax rules say that it is interpreted as (now with braces):

if (a) {
    if (b) {
        f();
    }
else {
    g();
}
}

which actually means:

if (a) {
    if (b) {
        f();
    }
    else {
        g();
    }
}

in case you wanted the other possibility, then you must use braces. For example you can write it this way:

if (a) {
    if (b)
        f();
}
else
    g();

which actually means:

if (a) {
    if (b) {
        f();
    }
}
else {
    g();
}

Note

As all elementary programming books recommend: If you are in doubt about operator precedence, then use parentheses; if you extend that to statements coding, if you are in doubt, use braces! :)

like image 44
Luis Colorado Avatar answered Sep 27 '22 19:09

Luis Colorado