Comment by jpcfl

17 hours ago

Bjarne should have called it ++C.

Nah. It's just the natural semantics -- he added stuff to C, but returned something that wasn't actually more advanced...

Because people choose to use pre-increment by default instead of post-increment?

Why is that?

  • It should be ++C because with C++ the value you get from the expression is the old one.

    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.

    • K&R seems to use pre-increment early on, then post-increment consistently (or a lot, anyway, I haven't done a thorough check) after chapter 3, in situations where either would do. In fact, after introducing post-increment at 2.8.

    • > It should be ++C because with C++ the value you get from the expression is the old one.

      You get it!

  • The PDP-11 that C originally targeted had address modes to support the stack. Pre-increment and post-decrement therefore did not require a separate instruction; they were free. After the PDP-11 went the way of the dodo, both forms took a machine cycle so it (mostly) became a stylistic issue. (The two operators have different semantics, but the trend to avoid side-effects in expressions means that both are most often used in a single expression statement like "++x;" or "x++;", so it comes down to your preferred style.)

  • Why would you use post increment by default? The semantics are very particular.

    Only on very rare occasions I need post increment semantics.

    And in those cases I prefer to use a temporary to make the intent more clear

    • I rarely use pre-increment tbh, but post-increment all the time for array indices (since typically the array should be indexed with the value before the increment happens).

      If the pre- or post-increment behaviour isn't actually needed, I prefer `x += 1` though.

    • People seem to mostly write a typical for loop ending with ; ++i){

      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.

      5 replies →

    • If you're used to the idiom, the intent couldn't be clearer.

      I miss it when switching between C/++ and other languages.

  • Why use this operator? Like most C and C++ features the main reason tends to be showing off, you learned a thing (in this case that there are four extra operators here) and so you show off by using it even if it doesn't make the software easier to understand.

    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.

    • They can be useful when adding things to an array in a loop. A trivial example which removes a character from a null terminated string:

        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.

      1 reply →