3

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.

choeger
  • 3,562
  • 20
  • 33

4 Answers4

2

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.

haccks
  • 104,019
  • 25
  • 176
  • 264
  • I don't understand the explanation. In the very first sentence you wrote it returns an l-value. and the dereference is evaluated first , just as in the second example, isn't it? so what's the difference? – Karoly Horvath Mar 21 '14 at 09:35
  • @KarolyHorvath; OK. Let me explain it a bit more. – haccks Mar 21 '14 at 09:38
  • I think the real explanation lies in the details of how the ternary operator works. – Karoly Horvath Mar 21 '14 at 09:41
  • @KarolyHorvath; No. I explained it in more detailed. – haccks Mar 21 '14 at 09:46
  • Sorry, but I do not understand your answer. In the first sentence you say (correctly) that * yields an l-value. In your last sentence you say (correctly) that * is evaluated before ++. And your conclusion is that this yields an r-value? So the order of evaluations effects the result-type of pointer dereference? – choeger Mar 21 '14 at 09:47
  • @choeger; In fact this is a little bit tricky. I edited the answer. Read it again. – haccks Mar 21 '14 at 09:48
  • So what is a "raw value" and why is it returned here? – choeger Mar 21 '14 at 09:51
  • OK. First answer me: Is this correct `int i = 0; (++i)++;` ? – haccks Mar 21 '14 at 09:53
  • *(&a) is equal a, * value at, & address at, so writing *(&a) is same as writing a and this must not returns L value error. – asifaftab87 Mar 21 '14 at 09:58
  • @asifaftab87; Then what? – haccks Mar 21 '14 at 10:00
  • It just simply returning the value stored in that location, if int a=10 and int *p=&a then *p=10, *(&a)=a=10. you can check. – asifaftab87 Mar 21 '14 at 10:01
  • @haccks: sry, I downvoted, there's no such thing as "raw value", I've found your explanation very confusing. after some googling.. see my answer. – Karoly Horvath Mar 21 '14 at 10:02
  • Indeed this has nothing to do with order of evaluation etc and everything to do with the obscure promotion rules of the ?: operator. – Lundin Mar 21 '14 at 10:04
  • @Lundin; Where did I said that this has something to do with order of evaluation? – haccks Mar 21 '14 at 10:05
  • @KarolyHorvath; I do not see how it is differ from while I tried to explain it. I am really disappointed by downvoes to this answer :( – haccks Mar 21 '14 at 10:08
  • @haccks: oh come on... I said it's because of the ternary operator you said **no**. "*ptr_b is evaluated before the increment applied to it and hence returns r-value" - this is just plain wrong. as I said, it's because of the ternary operator. and Lundin was right, you were referring to evaluation order, which is, again, wrong. – Karoly Horvath Mar 21 '14 at 10:13
  • @KarolyHorvath; No. `"*ptr_b is evaluated before the increment applied to it and hence returns r-value" ` is meant for the same that `?:` returns a r-value although its wording might be wrong and confusing. I just tried to explain this to OP. Regarding of your question that "the real explanation lies in the details of how the ternary operator works": I said no because I was fully concentrated at that time on the **operand of `++`** , which must be a l-value. – haccks Mar 21 '14 at 10:19
  • @haccks: so you see there's nothing wrong with the downvotes. don't worry, we *all* make mistakes. after all, we are humans ;) – Karoly Horvath Mar 21 '14 at 10:23
  • @KarolyHorvath; Yes :). But my intention was to give a clear explanation but I failed to do so, my bad. – haccks Mar 21 '14 at 10:25
2

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.

Community
  • 1
  • 1
Karoly Horvath
  • 94,607
  • 11
  • 117
  • 176
1

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

Community
  • 1
  • 1
Lundin
  • 195,001
  • 40
  • 254
  • 396
  • `ptr_a` and `ptr_b` both have the same type though, so no promotion would occur. – M.M Mar 21 '14 at 12:46
-1

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.

asifaftab87
  • 1,315
  • 24
  • 28