Takeaway #1: "C and C++ are different: don’t mix them, and don’t mix them up"
Takeaway #1: "C and C++ are different: don’t mix them, and don’t mix them up"
But I write ; i++){ and seeing it the other way round throws me off for a minute, because I think, as you put it, why would you use those very particular semantics?
But I guess this is only a semantic argument.
This is not one of those beginner -> journeyman -> expert cycles where coincidentally the way you wrote it as a beginner is identical to how an expert writes it but for a very different reason. I'd expect experts are very comfortable writing either { x = k; k += 1; } or { k += 1; x = k; } depending on which they meant and don't feel an itch to re-write these as { x = k++; } and { x = ++k; } respectively.
I'm slightly surprised none of the joke languages add equally frivolous operators. a%% to set a to the remainder after dividing a by 10, or b** to set b as two to the power b or some other silliness.
If you're asking why people use pre-increment by default instead of post-increment, it's mostly historical. The early C compilers on resource-constrained platforms such as early DOS were not good at optimization; on those, pre-increment would be reliably translated to a simple ADD or INC, whereas code for post-increment might generate an extra copy even if it wasn't actually used.
For C++ this was even worse with iterators, because now it depended on the compiler's ability to inline its implementation of postfix ++, and then prove that all the copies produced by that implementation have no side effects to optimize it to the same degree as prefix ++ could. Depending on the type of the underlying value, this may not even be possible in general.
The other reason is that all other unary operators in C are prefix rather than postfix, and mixing unary prefix with unary postfix in a single expression produces code that is easy to misunderstand. E.g. *p++ is *(p++), not (*p)++, even though the latter feels more natural, reading it left-to-right as usual. OTOH *++p vs ++*p is unambiguous.
The difference is that i++ has to keep a copy to the original around as the return value is the pre-increment value, while with ++i that isn't needed as the resulting value is being returned.
In the for loop that shouldn't matter as a) for an integer it is essentially for free (it is just reordering when the relevant register is set) and b) that value is hopefully optimized out anyways by the compiler, however as there are cases where it matters some people prefer the ++i style, some just think it looks better.
for(auto it = begin(v); it != end(v); ++it)
void remove_char(char *s, char c) {
size_t i, j;
for (i = j = 0; s[i] != '\0'; i++)
if (s[i] != c)
s[j++] = c;
s[j] = '\0';
}
This might be better expressed with a higher order filter function, but C is too low level for things like that.There are also idioms for stack manipulation using them: "stack[sp++] = pushed" and "popped = stack[--sp]".
C code does a lot of incrementing and decrementing by one, and so having dedicated syntax for it is convenient.
while(*d++ = *s++)
;
On the Motorola 68000 (based somewhat on the PDP-11) the code would look like: loop: move.b (a0)+,d0
move.b d0,(a1)+
bne loop
while on the x86 line, it would be: loop: mov al,[rsi]
mov [rdi],al
inc rsi ; extra instruction!
inc rdi ; extra instruction!
cmp al,0
jne loop
Yes, there are better ways to write that code for both the 68K and x86, but I hope this gets the point across.1. prefix incr/decr precedence: "stack[--sp]"
2. postfix incr/decr precedence: "s[j++]"
3. i have no particular preference for the precedence and am just using a shorthand I inherited from my ancestors whose use cases are no longer relevant to me: "i++" in your for loop
My rank speculation is that C programmers get in a habit of #3 and then forget to consider precedence in an expression where it matters.
In any case, it would be interesting to do a scan of github to see how often prefix and suffix incr/decr had to get switched up in a bugfix patch.
If the pre- or post-increment behaviour isn't actually needed, I prefer `x += 1` though.
* is it (*s)++ or *(s++)?
* it is not *++s nor ++*s
And I have seen *(*s)++
in some places!It is concise syntax but very confusing.
Although this may seem cryptic at first sight, the notational convenience is considerable, and the idiom should be mastered, because you will see it frequently in C programs.
I wonder sometimes why we keep insisting on the "OP ARG, ARG" format in general for assembly. Why not something like `MOV X -> Y` that would make it absolutely clear and unambiguous? For that matter, why not `COPY X -> Y`, since that's what it actually does?