37

In the 3.0.4 Linux kernel, mm/filemap.c has this line of code:

retval = retval ?: desc.error;

I've tried compiling a similar minimal test case with gcc -Wall and don't get any warnings; the behavior seems identical to:

retval = retval ? retval : desc.error;

Looking at the C99 standard, I can't figure out what formally describes this behavior. Why is this OK?

TRiG
  • 10,148
  • 7
  • 57
  • 107
Conrad Meyer
  • 2,851
  • 21
  • 24
  • 9
    Have a look at http://stackoverflow.com/questions/2806255/why-would-you-use-the-ternary-operator-without-assigning-a-value-for-the-true – vhallac Oct 18 '11 at 22:49
  • 3
    Thanks, vhallac. As far as I can tell, using this GCC extension is a tiny shortcut which completely destroys portability. – Conrad Meyer Oct 18 '11 at 23:07
  • Exactly what I said to a colleague who tried to use it on one of our projects. :) – vhallac Oct 18 '11 at 23:13
  • Doesn't the Bourne shell have a construct like this too? –  Oct 19 '11 at 01:10
  • @ConradMeyer: You might be right, in some cases. However, the Linux kernel developers early on made a conscious decision to require gcc, and the kernel currently depends on several non-C99 extensions. See http://kernel.org/doc/Documentation/Changes for kernel dependencies, as well as http://en.wikipedia.org/wiki/Linux_kernel#Programming_languages. – Avi Oct 19 '11 at 10:59
  • @Avi: What's right for the linux kernel and what's right for a userspace library are probably totally different things; agreeing on a single compiler (or a small set of approved compilers) is probably essential for kernel development anyways. While my question does refer to the linux kernel specifically, focusing on it wasn't my intent :-). – Conrad Meyer Oct 23 '11 at 20:52

4 Answers4

36

As several others have said, this is a GCC extension, not part of any standard. You'll get a warning for it if you use the -pedantic switch.

The point of this extension is not really visible in this case, but imagine if instead it was

retval = foo() ?: desc.error;

With the extension, foo() is called only once. Without it, you have to introduce a temporary variable to avoid calling foo() twice.

zwol
  • 135,547
  • 38
  • 252
  • 361
  • 14
    but retval = foo(); retval = retval ? retval : desc.error; is MUCH better and is 100% portable. – akappa Oct 18 '11 at 23:00
  • I really liked David Given's response as well, but this one clarifies the single evaluation semantics and tells me about `-pedantic` causing a warning. Chosen. – Conrad Meyer Oct 18 '11 at 23:05
  • 1
    @akappa: It's not better if you prefer to avoid introducing temporary variables. This is one of the *really old* extensions to GCC, and it reflects the functional-language tastes of GCC's original developers. Also, at the time, all local variable declarations had to be at the top of the function; "mixed declarations and code" wasn't standard till C99. – zwol Oct 18 '11 at 23:21
  • 1
    @Zack is there any document with the history of such obscure extensions? I would be interested in reading more about them, but I'm guessing its all buried in ancient logs from the GNU/GCC developer mailing lists. – crasic Oct 19 '11 at 01:27
  • Sorry, I'm not aware of any such document, and the public GCC development list archives only go back as far as EGCS - not nearly far enough for this one. Old issues of the [GNU's Bulletin](http://www.gnu.org/bulletins/bulletins.html) might have something, but other than that my only suggestion is to find and interview people who were with the FSF from the very beginning (1986). – zwol Oct 19 '11 at 03:45
  • 1
    @Zack: It might not have been a bad extension at the time, but that doesn't mean it isn't now. – Joren Oct 19 '11 at 09:56
  • I'm confused on why `foo()` would be evaluated twice. – sherrellbc Feb 06 '21 at 15:37
  • @sherrellbc Because, without the extension, you might be tempted to write `foo() ? foo() : desc.error` and that calls foo a second time if the first call returns a nonzero value. – zwol Feb 06 '21 at 21:34
20

It's a gcc extension. x ?: y is equivalent to x ? x : y --- see http://gcc.gnu.org/onlinedocs/gcc/Conditionals.html#Conditionals.

Yes, I think it's evil too.

David Given
  • 13,277
  • 9
  • 76
  • 123
  • Why do you say it's evil? Nonportable, yes, but it has an effect you can't get any other way (see my answer). – zwol Oct 18 '11 at 22:57
  • No, it's not evil! It's quite handy. – sidyll Oct 18 '11 at 22:57
  • 9
    @Zack: it's evil because it confuses people which doesn't know that non-portable and unnecessary syntax. – akappa Oct 18 '11 at 22:58
  • I'm willing to agree that it's evil :-). – Conrad Meyer Oct 18 '11 at 23:05
  • @akappa, not knowing the syntax doesn't make it evil, it simply makes the programmer ignorant (by the very definition of the word). JavaScript has a defaulting mechanism built into `||` which performs the same operation. understanding how the code works helps to produce code that is elegant in its simplicity. – zzzzBov Oct 19 '11 at 02:28
  • 3
    It's not *that* evil. It's kinda equivalent to C#'s `??` operator for nullable types. – Chris Burt-Brown Oct 19 '11 at 08:22
  • 1
    @zzzzBov: ignorance of a GNU-specific C __extension__, that's the point. – akappa Oct 19 '11 at 09:32
  • @akappa, I'm just making the point that this feature exists in other languages, and in some languages it uses the same syntax. It's syntactic sugar similar to how the `+=` operator is syntactic sugar. – zzzzBov Oct 19 '11 at 13:21
  • 2
    @zzzzBov: I understand. I just wanted to make clear that I don't find it evil __per se__, but I find it evil because it is an extension which confuses people which does not know GNU C. – akappa Oct 19 '11 at 13:41
7

This is a GCC extension called Conditionals with Omitted Operands. Omitting the middle operand has the effect of using the value of the conditional as the omitted operand without evaluating it again. It is safe to use even if the conditional is a macro.

David Schwartz
  • 179,497
  • 17
  • 214
  • 278
3

This is a gcc-specific extension to C and is not standard.

Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285