Are compound statements (blocks) surrounded by parens expressions in ANSI C?
Asked Answered
Y

2

45

Browsing the Linux kernel sources I found some piece of code where a block of statements surrounded by parenthesis is treated as a expression a la lisp (or ML), that is, an expression which value is the value of the last statement.

For example:

int a = ({
    int i;
    int t = 1;
    for (i = 2; i<5; i++) {
        t*=i;
    }
    t;
});

I've been looking at the ANSI C grammar trying to figure out how this piece of code would fit in the parse tree, but I haven't been successful.

So, does anybody know if this behaviour is mandated by the standard or is just a peculiarity of GCC?

Update: I've tried with the flag -pedantic and the compiler now gives me a warning:

warning: ISO C forbids braced-groups within expressions
Yand answered 6/8, 2009 at 10:6 Comment(0)
S
38

It's called "braced-group within expression".

It's not allowed by ANSI/ISO C nor C++ but gcc supports it.

Scold answered 6/8, 2009 at 10:15 Comment(4)
You can suppress the warning in GCC by putting __extension__ before the opening parenthesis.Hysterics
@Hysterics why isn't that an answer?Gobelin
__extension__ helps, but NOT when the statement is used at the global scopeGodforsaken
@hellow: Because it doesn't solve the problem; it just wall-papers over it.Allanson
M
43

This is not standard C. It is a gcc extension called statement expressions. You can find the complete list of C extensions here. This is actually one of the many gcc extensions used in the Linux kernel and it seems like clang supports this too and although it is not explicitly named in the document.

As you observed the last expression serves as the value of the expression, the document says (emphasis mine):

The last thing in the compound statement should be an expression followed by a semicolon; the value of this subexpression serves as the value of the entire construct. (If you use some other kind of statement last within the braces, the construct has type void, and thus effectively no value.)

One of the main benefits would be to make safe macros that would avoid multiple evaluations of arguments with side effects. The example given uses this unsafe macro:

#define max(a,b) ((a) > (b) ? (a) : (b))

which evaluates either a or b twice and can be rewritten to eliminate this problem using statement expressions as follows:

#define maxint(a,b) \
   ({int _a = (a), _b = (b); _a > _b ? _a : _b; }) 

Note, the need to explicitly use int which can fixed using another gcc extension Typeof:

#define max(a,b) \
   ({ typeof (a) _a = (a), _b = (b); _a > _b ? _a : _b; }) 

Note that clang also supports typeof.

Megacycle answered 19/9, 2013 at 3:11 Comment(4)
Is it possible to write a macro to be safe like that without statement expressions?Hysterics
@Hysterics I don't think so but I would not consider myself a macro expert. I avoid them as much as I can, although there are some cases they are hard to avoid such as rolling your own assert.Megacycle
@Hysterics That depends on what you want your macro to do, in some cases it's certainly possible to write a safe macro. For the complete max functionality you'll fall short in someway no matter what you do in standard C - the problem is that you either need to know the type of the arguments or you have to evaluate one of them twice (of which the later is the problem with the macro approach above).Mealtime
Hmpf, the last one should be modified to properly support heterogenous arguments.Luthanen
S
38

It's called "braced-group within expression".

It's not allowed by ANSI/ISO C nor C++ but gcc supports it.

Scold answered 6/8, 2009 at 10:15 Comment(4)
You can suppress the warning in GCC by putting __extension__ before the opening parenthesis.Hysterics
@Hysterics why isn't that an answer?Gobelin
__extension__ helps, but NOT when the statement is used at the global scopeGodforsaken
@hellow: Because it doesn't solve the problem; it just wall-papers over it.Allanson

© 2022 - 2024 — McMap. All rights reserved.