0

I found the following construct, where a variable is assigned to what seems to be a compound statement, foo, in a driver. For comparison, bar yields undefined behaviour be treating the same code as a proper function. It doesn't seem to conform with my understanding of the C language and its preprocessor, so I suspect that it is a GCC extension. What is the logic executed here? (See output here.)

#include <stdio.h>

#define foo(c) ({ int x = c; x; })

int bar(char c) {
    int x = c;
    x;
}

int main(void) {
    int x = foo('0');
    int y = bar('A');
    printf("%d\n%d\n", x, y);
    return 0;
}

Output:

48
0
einpoklum
  • 118,144
  • 57
  • 340
  • 684
nwn
  • 583
  • 7
  • 23
  • 1
    As you already suspect a gcc extension, why did you not check the documentation before asking? What else did you do to find out? – too honest for this site Feb 03 '17 at 00:25
  • @Olaf I did try extensive searching, but couldn't find the keywords to yield a result. I was able to find sources for the UB I suspected from the function version given, but this wasn't quite the same as the macro version. I browsed through the GCC manual, but didn't find the specific reference to it as there are sufficiently many extensions to make a linear search difficult. Moreover, I also consulted with some colleagues in person who were unaware of this construct. I believe I conducted enough research to merit this question. – nwn Feb 03 '17 at 01:02
  • Less than 5 minutes of searching leads to https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html#Statement-Exprs which includes the terms "statement" and "declaration" which is exactly what you have above. How to properly search is a basci skill when it comes to programmning and many other fields. Sidenote: see [ask], you should show your effort in your question! – too honest for this site Feb 03 '17 at 17:03
  • Knowing now the answer, it is trivial to find this. My searching abilities seem to have failed me yesterday. Thanks for the feedback. – nwn Feb 03 '17 at 17:43

2 Answers2

2

There are two different things involved here.

Firstly, the so called "statement expression" ({ int x = c; x; }), which is a GCC extension. This expression in GCC evaluates to the well-defined value of x. The value it evaluates to is defined by the last expression inside the ({...}), which is x in your case. (BTW, the preprocessor has little to do with it. You don't have to involve preprocessor to use statement expressions in GCC.)

Secondly, your function bar, which is declared to return int but lacks a return statement. This has nothing to do with any extensions. This function does not return any defined value. If the calling code attempts to use the value returned by bar, the behavior is undefined. The x expression at the end of bar is just a no-op that does not change anything.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
2

It is indeed a GCC extension and it is described in the GCC manual. Where an expression is expected, you can supply a brace-surrounded block as a valid expression whose value is the last expression in the block.

C does not automatically insert a return in an expression statement at the end of a function, so bar is indeed UB. GCC does not implement any extension which does that either. But the following would be legal with the GCC extension:

int bar(char c) {
  return ({
    int x = c; 
    x; 
  });
}
Grzegorz Szpetkowski
  • 36,988
  • 6
  • 90
  • 137
rici
  • 234,347
  • 28
  • 237
  • 341