Question

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.

Was it helpful?

Solution 3

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.)

OTHER TIPS

In C, the ternary operator always returns an r-value - Conditional operator differences between C and C++

In the second example, you directly apply post-increment to it, but that operator expects an l-value, so it's not a valid code.

In the first example, you do pointer dereferencing, which turns it to an l-value, hence the code is valid.

Note that the derefernce * operator returns a l-value when applied to a pointer.
In case of

(*(argc <= 1 ? &a : &b))++;

Either &a or &b is returned (a r-value but, a pointer will be returned). After that the derefernce is applied on either of two pointer and this will return a l-value. Increment operator can applied to it as its need a l-value as its operand.
You can also understand this as; if argc = 1, then the expression would be like

*(&a);

&a returns the address of a and deferencing it will return a l-value.

In case of

(argc <= 1 ? *ptr_a : *ptr_b)++;  

*ptr_a or *ptr_b is returned (in this case a r-value is returned). As the operand of increment operator ++ must be a l-value, the above statement will produce error.

Suppose

  int a = 0, b = 1;
  int *ptr_a = &a;
  int *ptr_b = &b;

we can increase the value of variable means having some location. If you try to modify a constant then you get error L value required means Location required and constants do not have any location and hence the error.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top