There are times I would call Halloween when programming C. It is when you would expect ghosts dancing in your yard and you can do nothing about it. The combination of “++” and “*” is one of the worst. I have been arguing against this way of coding for a long time because I believe every piece of code should be readable by HUMAN. (yes, not COMPILERS!)
However, this coding style appears regardless of my willingness. Therefore, I have to write about all the possible (ugly) usage of the combinations here.
Rules
DO NOTICE THAT WHEN IT COMES TO PREFIX INC/DEC, POSTFIX INC/DEC, AND DEREFERENCE, C AND C++ SHARE THE SAME RULE.
Precedence | Operator | Description | Associativity |
---|---|---|---|
1 | ++/- - | Suffix/postfix increment and decrement | Left to Right |
2 | ++/- - | Prefix increment and decrement | Right to Left |
2 | * | Indirection (dereference) | Right to Left |
The Easy Part
The postfix and prefix are complicated enough. Fine, it’s not easy at all. So I decided to write them first.
Suppose we have:
int i = 10;
++i
i += 1;
return i;
i++
int tmp = i;
i += 1;
return tmp;
Hallowing
We suppose we have:
int* p = head;
we will expand the operation as a simple function. But do notice that this DOES NOT mean that the compilers will compile these operators this way. This is just a show of concept how these operators work.
*++p
Prefix increment get executed first, and the result value is returned for dereference.
p = p + 1;
assert(p == head + 1);
return *p;
++*p
Dereference get executed first, then we would increment the object itself and return the result.
assert(p == head);
*p = *p + 1;
return *p; // *p has been incremented.
*p++
Postfix increment has higher precedence. Yet the result is not returned. So the dereferenced object is the one pointed by original p.
int* tmp = p;
p = p + 1;
assert(p == head + 1);
return *tmp;
*(p++)
Postfix increment has higher precedence, it doesn’t change with the presence of parentheses. Same as *p++.
(*p)++
ALMOST the same with ++*p. But the increment is changed to postfix one, so the return value changed. The parentheses have higher precedence, thus dereference is carried first, then postfix increment.
assert(p == head);
int tmp = *p
*p = (*p) + 1;
return tmp;
Experiment
You may download this code and Makefile form the link provided.
#include <stdio.h>
void printResult(const char* op, int* head, int retVal, int* p){
printf("op: %s.\t head[0]==%d, head[1]==%d, retVal==%d, *p==%d\n",
op, head[0], head[1], retVal, *p);
}
int main() {
int head[2];
int *p;
int retVal;
head[0] = 10; head[1] = 20;
p = head; retVal = *++p;
printResult("*++p" , head, retVal, p);
head[0] = 10; head[1] = 20;
p = head; retVal = ++*p;
printResult("++*p" , head, retVal, p);
head[0] = 10; head[1] = 20;
p = head; retVal = *p++;
printResult("*p++" , head, retVal, p);
head[0] = 10; head[1] = 20;
p = head; retVal = *(p++);
printResult("*(p++)", head, retVal, p);
head[0] = 10; head[1] = 20;
p = head; retVal = (*p)++;
printResult("(*p)++", head, retVal, p);
return 0;
}
and we can get the following result:
op: *++p. head[0]==10, head[1]==20, retVal==20, *p==20
op: ++*p. head[0]==11, head[1]==20, retVal==11, *p==11
op: *p++. head[0]==10, head[1]==20, retVal==10, *p==20
op: *(p++). head[0]==10, head[1]==20, retVal==10, *p==20
op: (*p)++. head[0]==11, head[1]==20, retVal==10, *p==11
Also, I am happy to find that the result from C and Cpp compiler are the same. (Off course.)
Reference
C Operator Precedence
C++ Operator Precedence
Difference between ++*p, *p++ and *++p