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?
    – Lorraine
    May 15, 2021 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, 2021 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, 2021 at 17:55
  • 2
    Looks like internal code reuse in the compiler. May 16, 2021 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, 2021 at 1:59

1 Answer 1

9

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.

3
  • 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, 2021 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, 2021 at 1:06
  • SunOS 3.4 (1986) C compiler allows casts on the left-hand side. (int)status = RPC_INTR; will compile. The approximate predecessor of SunOS, 4.2BSD, C compiler didn't allow that. This could be a clue to the origin of LHS casts. May 17 at 23:07

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .