Search code examples
cdereferencelvalue

How does C infer "assignable values" / l-values


This just puzzled me:

#include <stdio.h>

int main(int argc, char** argv) {
  int a = 0, b = 1;
  int *ptr = argc <= 1 ? &a : &b;
  (*ptr)++; //does work, of course

  (*(argc <= 1 ? &a : &b))++; //inlining, does also work

  int *ptr_a = &a;
  int *ptr_b = &b;

  (*(argc <= 1 ? ptr_a : ptr_b))++; //variables carry "assignability"

  (argc <= 1 ? *ptr_a : *ptr_b)++; //if-expression does not carry "assignability"?

  return 0;
}

I always assumed that "assignability" is a type-property. Hence I thought the last statement should work just fine, instead it is rejected. So why does the dereference have to be the outermost operator for a C-compiler to figure out that the lhs is actually a memory location?

edit: I doubt it has something to do with OS/compiler but the C standard, but here is my compiler setup:

clang version 3.3 (tags/RELEASE_33/final)
Target: x86_64-redhat-linux-gnu
Thread model: posix

And here is the error:

test.c:15:32: error: expression is not assignable
  (argc <= 1 ? *ptr_a : *ptr_b)++; //if-expression does not carry "assignability"?

edit2: What interests me most is, why C seems to carry the "assignability" property through some but not all expressions.


Solution

  • The problem is that the conditional operator in C promotes the 2nd and 3rd operands to match each other. A promoted variable is a rvalue and not a lvalue, so the ?: always returns a rvalue.

    The * operator on the other hand, returns a lvalue. That is why (*(argc <= 1 ? ptr_a : ptr_b))++ works, because ++ is applied to the result of * which is a lvalue.

    But in the case of (argc <= 1 ? *ptr_a : *ptr_b) the result is a rvalue so ++ cannot be used.

    (Please note that C and C++ are different in this case.)