9

Soon after learning the C language in the late 80s, before an ANSI C compiler was available on the machines I was using, it occurred to me to check if the following compiles

int a, b, c;
foo() {
    (a == 0 ? b : c) = 1;
}

and it did! The compiler has propagated the Lvalue property of the last two operands of the ternary expression to the expression itself. For a while, I amused people by demonstrating them that "Easter egg" in the compiler.

Now, of course, according to the ANSI C standard, we have to write *(a == 0 ? &b : &c).

However, I cannot remember or figure out which compiler it was. The original K&R compiler I tried on an online PDP-11 simulator says "3: Lvalue required", as well as a compiler used in BSD 2.9 (PCC-based, I guess?).

It could have been a compiler on MS-DOS, but I remember that at least one compiler on a UNIX platform also allowed that.

I'm not trying to find out exactly which one it was in my case, or which one was the earliest; an example of a pre-ANSI C compiler written in the 70-80s for any commercially-available platform/OS which existed at the time and which compiles the above test case would be enough.

Googling "lvalue ternary expression" yields discussions about the fact that a ternary expression can be an Lvalue in C++ but not in the contemporary C.

10
  • 1
    Which machine were you using?
    – OmarL
    May 15 at 16:10
  • @OmarL Which machines, rather. IBM PC clones, mostly. Also there was at least one obscure UNIX-like workstation with a non-x86 CPU (not by Sun).
    – Leo B.
    May 15 at 16:14
  • 6
    Pet gripe: it's the conditional operator in a conditional expression. Calling it "the operator with three operands" is just silly. May 15 at 17:55
  • 2
    Looks like internal code reuse in the compiler. May 16 at 20:26
  • 1
    It has to be possible to 'balance' (as we used to say in Algol-68 circles) the expression to a single type. May 18 at 1:59
8

The first gnu C compilers predate the ANSI C Standard, and unless invoked with the -pedantic flag would ease many restrictions which the authors viewed as, well pedantic. I don't remember for certain if the ability to treat ternary expressions as lvalues was among them, but I think it was, along with the ability to treat certain cast expressions as lvalues in cases where the operands were likewise. I think the guiding philosophy was that if there was only one thing a construct could sensibly mean, and the construct might be useful, it should have that meaning. Very different from the philosophy of gcc's maintainers today.

2
  • 1
    IIRC, my experience of this construct being allowed by a compiler predates my acquaintance with GCC, so if you're right, GCC was likely not the only one or the first one.
    – Leo B.
    May 17 at 23:09
  • GCC 1.21, circa 1988, indeed documents such an extension. GCC 0.9 is the next earlier version that seems to be readily available; it doesn't document any extensions, but it's not so easy to build it to test whether it supports this. Sep 2 at 1:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.