While it did once have some performance implications, I think the real reason is for expressing your intent cleanly. The real question is whether something while (*d++=*s++);
expresses intent clearly or not. IMO, it does, and I find the alternatives you offer less clear -- but that may (easily) be a result of having spent decades becoming accustomed to how things are done. Having learned C from K&R (because there were almost no other books on C at the time) probably helps too.
To an extent, it's true that terseness was valued to a much greater degree in older code. Personally, I think this was largely a good thing -- understanding a few lines of code is usually fairly trivial; what's difficult is understanding large chunks of code. Tests and studies have shown repeatedly, that fitting all the code on screen at once is a major factor in understanding the code. As screens expand, this seems to remain true, so keeping code (reasonably) terse remains valuable.
Of course it's possible to go overboard, but I don't think this is. Specifically, I think it's going overboard when understanding a single line of code becomes extremely difficult or time consuming -- specifically, when understanding fewer lines of code consumes more effort than understanding more lines. That's frequent in Lisp and APL, but doesn't seem (at least to me) to be the case here.
I'm less concerned about compiler warnings -- it's my experience that many compilers emit utterly ridiculous warnings on a fairly regular basis. While I certainly think people should understand their code (and any warnings it might produce), decent code that happens to trigger a warning in some compiler is not necessarily wrong. Admittedly, beginners don't always know what they can safely ignore, but we don't stay beginners forever, and don't need to code like we are either.
prefix and postfix are not necessary, they are just shortcuts.
y = x++;
means
y = x;
x = x + 1;
however
y = ++x;
means
x = x + 1;
y = x;
Likewise, calling the function f as f(x++)
is not the same as saying f(++x)
Best Answer
Both pre- and postfix have basically the same advantages over infix notation. The most important of these are:
much easier to translate to a format that is suitable for direct execution. Either format can trivially be turned into a tree for further processing, and postfix can be directly translated to code if you use a stack-based processor or virtual machine
entirely unambiguous. Infix notation requires precedence and associativity rules to disambiguate it, or addition of extra parentheses that are not usually considered part of the notation. As long as the number of arguments to each operator are known in advance, both prefix and postfix notation are entirely unambiguous: "* + 5 6 3" is (5+6)*3, and cannot be interpreted as 5+(6*3), whereas parenthesis is required to achieve with infix.
supports operators with different numbers of arguments without variation of syntax. "unary-op 5" and "ternary-op 1 2 3" both work fine, but need special syntax to make them work in infix.