10

I came across this program via a quora answer

 #include<stdio.h>
 int main() {
    printf("%d\n", ( { int n; scanf("%d", &n); n*n; } ));
    return 0;
 }

I was wondering how does this work and if this conforms the standard?

Grijesh Chauhan
  • 57,103
  • 20
  • 141
  • 208
Quixotic
  • 2,424
  • 7
  • 36
  • 58
  • 3
    C99 Strict: http://ideone.com/9K9bcV and C http://ideone.com/PdalsH My IDE C compiler declares a bunch of errors and warnings on this. Interested why the second link compiles. –  Apr 26 '13 at 15:54
  • @Armin the link uses gcc, which by default uses GNU C89. – effeffe Apr 26 '13 at 16:09
  • Not answer to your question But it work with gcc here I written similar codes [**First**](http://codepad.org/POu848fV) and [**Second**](http://codepad.org/MFLG9sa7) , Remember in [**`int i = (5, 7);` `i` would be `7`**](http://stackoverflow.com/questions/15302789/c-explain-ifexit0-0-line-of-code/15303040#15303040) – Grijesh Chauhan Apr 26 '13 at 16:19

3 Answers3

7

This code is using a "GNU C" feature called statement-expressions, whereby a parentheses-enclosed compound statement can be used as an expression, whose type and value match the result of the last statement in the compound statement. This is not syntactically valid C, but a GCC feature (also adopted by some other compilers) that was added presumably because it was deemed important for writing macros which do not evaluate their arguments more than once.

You should be aware of what it is and what it does in case you encounter it in code you have to read, but I would avoid using it yourself. It's confusing, unnecessary, and non-standard. The same thing can almost always be achieved portably with static inline functions.

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
0

I don't believe it does work... n has local scope within the braces... when you exit the braces, n becomes undefined though I suppose is could still exist somewhere on the stack and might work. It's begging for implementation issues and I guarantee is implementation dependent.

One thing I can tell you is that anyone working for me who wrote that would be read the riot act.

K Scott Piel
  • 4,320
  • 14
  • 19
  • It works. Just paste it into a file and compile (even works using `-ansi` flag in gcc). It sure is bad style though. – PaulProgrammer Apr 26 '13 at 15:59
  • There are lots of things that "work" -- doesn't mean they are valid. I can see how the last `n*n` might leave a value on the stack, but I'll guarantee there's no shortage of C implementations that won't even compile it. – K Scott Piel Apr 26 '13 at 16:00
  • 1
    @PaulProgrammer that flag is not enough, you have to use `-pedantic` if you want a warning for non-standard things like that. That code is *not* C. – effeffe Apr 26 '13 at 16:05
  • 1
    GCC options like `-std=c89` (aka `-ansi`) or `-std=c99` only attempt to ensure that all conforming programs will be interpreted correctly, by disabling extensions which conflict with the standard interpretation (such as treating `asm` or `attribute` as a keyword). They don't go out of their way to reject non-conforming programs. `-pedantic-errors` is the closest thing you have to a "reject non-conforming programs" option in GCC. – R.. GitHub STOP HELPING ICE Apr 26 '13 at 16:10
  • Anyway, I think that the behavior is well defined in gcc, and I hope so for every compiler supporting such a statement. When you exit the braces, you're not using anymore `n`, but the value of the last expression, which is `n * n`. – effeffe Apr 26 '13 at 16:15
  • @effeffe: Indeed, the behavior is well-defined on GNU C compilers. – R.. GitHub STOP HELPING ICE Apr 26 '13 at 16:32
0

It works. I get no warnings from gcc, so I suppose that it conforms to the standard.

The magic is the closure:

{ int n; scanf("%d", &n); n*n; }

This nugget scans an integer from the console (with no error checking) and squares it, returning the squared number. In ancient implementations of C, the last number on the stack is returned. The n*n puts the number on the stack.

That value gets passed to the printf:

printf("%d\n", <scanned>);

So, to answer your questions: Yes, it works. Yes, it's "standard" (to the extent that anyone follows the standard entirely). No, it's not a great practice. This is a good example of what I by knee-jerk reaction call a "compiler love letter", designed mostly to show how smart the programmer is, not necessarily to solve a problem or be efficient.

PaulProgrammer
  • 16,175
  • 4
  • 39
  • 56