51
int i = 3;
int j = (i)++;

vs

int i = 3;
int j = i ++;

Is there a difference between how the above two cases are evaluated?

Is the first case equivalent to incrementing an rvalue or is it undefined behaviour?

Polaris000
  • 938
  • 1
  • 11
  • 24
  • 18
    Seemingly arbitrary usage of parentheses is common in macro definitions. Where they *do* make a big difference, you'd like the error message you get. Well, usually. – Hans Passant Feb 27 '19 at 16:38
  • 3
    There is no difference in those for ints. However, it is not always the case and you must be cautious when combining brackets and operators, @govin-parmar have shown a good example what can happen with pointers. – Tomasz Kornuta Feb 28 '19 at 03:20
  • 1
    To be clear, *both* of these cases are well-defined (i.e., not UB) and will store 3 in `j`. – osuka_ Feb 28 '19 at 15:09
  • 1
    "*am I overthinking it*" yes. – alk Mar 05 '19 at 20:10

2 Answers2

97

i++ and (i)++ behave identically. C 2018 6.5.1 5 says:

A parenthesized expression is a primary expression. Its type and value are identical to those of the unparenthesized expression. It is an lvalue, a function designator, or a void expression if the unparenthesized expression is, respectively, an lvalue, a function designator, or a void expression.

The wording is the same in C 1999.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • 2
    For completeness, has this always been the case? I mean, I know it has, but your reference says C 2018 (i.e. the latest version), so it can't hurt to have it spelled out. – Mr Lister Feb 28 '19 at 07:17
  • 7
    @MrLister Yes, even pre-ANSI C (1978) had this behavior. It's not spelled out formally (so little was), but it's required for some examples in the first edition of K&R, such as `(*ptr)++`. – Sneftel Feb 28 '19 at 09:10
56

In your simple example of i++ versus (i)++, there is no difference, as noted in Eric Postpischil's answer.

However, this difference is actually meaningful if you are dereferencing a pointer variable with the * operator and using the increment operator; there is a difference between *p++ and (*p)++.

The former statement dereferences the pointer and then increments the pointer itself; the latter statement dereferences the pointer then increments the dereferenced value.

Govind Parmar
  • 20,656
  • 7
  • 53
  • 85
  • 7
    So for example, if you define a macro `#define postinc(x) x++` then `postinc(*p)` will not do what you expect given the function-like notation. That's why in writing macros it's common to heavily parenthesize e.g. `#define postinc(x) ((x)++)` – Daniel Schepler Feb 28 '19 at 01:12
  • 12
    Your answer boils down to "parenthesis can be used to enforce operator precedence" which is obvious and not what the OP asked. – Giacomo Alzetta Feb 28 '19 at 09:53
  • 3
    @GiacomoAlzetta There was a lengthy discussion on this answer that was removed by moderation. The short of it is that I felt that explaining this particular nuance is important because mixing these two expressions up in particular is a common source of bugs for beginners in C. – Govind Parmar Feb 28 '19 at 12:05
  • 7
    @GiacomoAlzetta Remember, SO answers are supposed to be useful for anyone reading the question, not just the OP or people already familiar with the technology being asked about. In my experience the most common usage of `(expr)++` is to increment a dereferenced value, so giving beginners the impression that `expr++` is equivalent is detrimental. – Govind Parmar Feb 28 '19 at 12:12
  • I.e. `*p++` is equivalent to `*(p++)`? – Solomon Ucko Feb 28 '19 at 15:44
  • 3
    @SolomonUcko No, the first would dereference the pointer and then increment it. The second would increment the pointer THEN dereference it. – ale10ander Feb 28 '19 at 20:21
  • @ale10ander So it is impossible to add parentheses within `*p++` without changing the meaning? – Solomon Ucko Feb 28 '19 at 20:31
  • 2
    @SolomonUcko Sure, `(*p++);` – Govind Parmar Feb 28 '19 at 20:32
  • @GovindParmar That wouldn't be within it; it would be around it. Also, where would this be covered in the specifications? – Solomon Ucko Feb 28 '19 at 20:33
  • @ale10ander Actually, when would the order of those operations matter *in C*? Post-increment returns the original value. Supporting references: https://stackoverflow.com/a/9255177/5445670, https://denniskubes.com/2012/08/14/do-you-know-what-p-does-in-c/, https://en.cppreference.com/w/c/language/operator_precedence, [https://www.quora.com/What-is-the-difference-between-*p++-and-++*p-in-pointers-of-c++/answer/Gajanan-Hegde](https://www.quora.com/What-is-the-difference-between-*p++-and-++*p-in-pointers-of-c++/answer/Gajanan-Hegde) – Solomon Ucko Mar 01 '19 at 03:15
  • The statement is correct but does not answer the question. There are more pitfalls with ++. – alk Mar 05 '19 at 20:14