Thread: difference between ++*x and x*++

  1. #1
    Registered User
    Join Date
    Apr 2019
    Posts
    808

    difference between ++*x and x*++

    i forget when it was but recently i asked about why x++ generated a warning but *x += 1 doesn't it was explained to me that the ++ operator has higher precedence than the * (or the other way round, i just made a mental note not to do it in general) so by writing *x++ you were incrementing the pointer by 1 not the value it pointed to. however i have just typed out a program in the c unleashed book using an array of functions to play with it and in each function the author writes ++*x (as an example) i thought to myself ah-ha this isn't going to work but it did. as an experiement i changed all the ++*const to *const++ and sure enough i got the warning i expected in the first place.

    as far as i understand it ++x increments x before using it and x++ increments x sometime after using it but before the line of code is finished executing (hence the use of x++ in for loops and the such).

    question arises then is why does ++*x increment the value that *x is pointing to and *x++ increments the pointer *x

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by cooper1200
    question arises then is why does ++*x increment the value that *x is pointing to and *x++ increments the pointer *x
    It's a matter of syntax. In ++*x the syntax is such that there's no way to interpret the increment as applying to x rather than *x, hence it is equivalent to ++(*x). In *x++ there are two possible interpretations: (*x)++ vs *(x++), and precedence rules say that the latter is the correct interpretation of the syntax, hence the increment applies to x, not *x.

    By the way, don't say "the pointer *x" unless you mean that *x is itself of a pointer type. If you want to refer to x as being the pointer, say "the pointer x". Likewise, "the value that *x is pointing to" means that *x is a pointer and you're talking about **x. Rather, say "the value that x is pointing to", or just say *x.
    Last edited by laserlight; 06-07-2019 at 05:26 AM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    Apr 2019
    Posts
    808
    ok suppose x is a pointer to an array element and for some reason i want to point at the next element before i use the value that x is pointing to would i have to write two lines of code ie
    Code:
    *x++;
    //now do something with it
    or could i write ++(*x)
    coop

  4. #4
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Code:
    #include <stdio.h>
    
    int main(void)
    {
        int numbers[] = {0, 1, 2};
    
        {
            // Option #1
            int *x = numbers;
            ++x;
            printf("%d\n", *x);
        }
    
        {
            // Option #2
            int *x = numbers;
            x++;
            printf("%d\n", *x);
        }
    
        {
            // Option #3
            int *x = numbers;
            printf("%d\n", *++x);
        }
    
        {
            // Option #4
            int *x = numbers;
            printf("%d\n", *(++x));
        }
    }
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  5. #5
    Registered User
    Join Date
    May 2019
    Posts
    214
    @cooper1200,

    What laserlight pointed out is that the statement is ambiguous to human eyes. It should not be used without parenthesis because of it.

    Where int * x; is the type:

    If you intend to increment the pointer, be clear always with *(x++) or *(++x), and if you want to increment the integer it points to be clear by explicating it with (*x)++. This way you and everyone else has less question as to your intent without reviewing the operator precedence rules.

    However, it is worse than just this. There are no absolute guarantees about when the increment is performed, which means optimization settings can change the order of things. This means it's not unambiguous to combine increments with other operations, and a de-reference is a separate operation from the increment in these clauses, so:

    int z = ++i + ++i;

    v[i] = ++i;
    v[++i] = i;
    can't really be relied upon, every time, for the order in which these increments are actually performed. It may be shorter to write these clauses, but various formations of this kind of writing can be quite tricky to recognize as a bug, especially where it works as expected in debug mode but fails in release mode (due to optimizations changing the order of events).

    The basic notion for coding standards is to use ++, pre and post, in isolation (separated by statements). It may be more "longhand", but it makes the code more obvious and can eliminate undefined order of evaluation issues.

    For example, in the last clause of a typical for loop, you'll often find: for( int n=0; n < x; ++n ). In this case, n is incremented in isolation. There's no ambiguity about when the increment will be performed.

    Stroustrup puts it this way (I paraphrase): The order of evaluation of sub-expressions is designed for the optimizer rather than the programmer. One should avoid complicated expressions wherever possible to be clear. A simple rule which ends these problems is: do not read or write to a value twice in the same expression.

    That's exactly what *(x++) or (*x)++ does, it writes (increments) and reads (dereferences) upon the same pointer twice in one clause. It's actually a bad habit, because to use this, one needs something like a = *(x++), which should work just fine, but if you THEN make it a = *(x) * *(x++), there may be no guarantee left as to WHEN the increment will be performed under all configurations of the compiler.

    Another point students don't quite realize happens with ++ (especially post, like n++) is applied to a class instantiation. This implies a copy is to be made for the increment. Optimizers should skip that, but there may be performance implications using post increment in all cases where it doesn't matter. When it doesn't matter, the habit should be pre, not post increment.
    Last edited by Niccolo; 06-07-2019 at 06:25 AM.

  6. #6
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Niccolo
    but if you THEN make it a = *(x) * *(x++), there may be no guarantee left as to WHEN the increment will be performed under all configurations of the compiler.
    It is guaranteed that the behaviour is undefined.

    Quote Originally Posted by Niccolo
    Another point students don't quite realize happens with ++ (especially post, like n++) is applied to a class instantiation. This implies a copy is to be made for the increment. Optimizers should skip that, but there may be performance implications using post increment in all cases where it doesn't matter. When it doesn't matter, the habit should be pre, not post increment.
    This is the C programming forum, so this consideration is not relevant.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  7. #7
    Registered User
    Join Date
    Feb 2019
    Posts
    1,078
    Quote Originally Posted by cooper1200 View Post
    question arises then is why does ++*x increment the value that *x is pointing to and *x++ increments the pointer *x
    In another question we told you about precedence and associativity of expressions. laserlight draws my attention to my confusion about "evaluation" and "grouping", and she's right (just remember, I am not a native english speaker - my examples showed the grouping!)...

    The fact is, in every expression you must deal with precedence and associativity. Taking *x++ as example, the post-increment operator ++ has precedence over * indirection operator, so the compiler will separate these operations as *(x++). Taking ++*x as example, the pre-increment operator has the same precedence of the * indirection operator... Here comes the associativity: both operator have right to left associativity, so the expression is ++(*x).

    Take a look in another classic example... Supose you have a simple structure:
    Code:
    struct s { int *xp; } s, *p;
    int a = 1;
    s.xp = &a;
    p = &s;
    What pointer is being derreferenced, if you do this?
    Code:
    int y = *p.x;
    Here, the access member operador (.) has precedence over the indirection operator *, so the expression is:
    Code:
    int y = *(p.x);
    If you want to a derreference to the p pointer you must do:
    Code:
    int *yp = (*p).x;
    That's why in the late 80's, the ANSI comitee extended C language adding the -> operator (with the same precedence as the (.) operadtor). To avoid the use of parentesis and the confusion you can write:
    Code:
    int y = *p->x;
    Here, '->' has precedence over * and you are derreferencing the x member, not p.

    So, always pay attention to precedence and associativity. They are important!

  8. #8
    Registered User I C everything's Avatar
    Join Date
    Apr 2019
    Posts
    101
    Maybe its just me,but singlestep some code in debugger makes me understand how the code and machine works better than human explaining
    you tell me you can C,why dont you C your own bugs?

  9. #9
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    That's not wrong, but when you run into the kind of undefined behaviour that Niccolo mentioned, it won't help you.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  10. #10
    Registered User
    Join Date
    Apr 2019
    Posts
    808
    when who runs into undefined behaviour?

  11. #11
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Anyone who uses expressions with such side effects in complex expressions.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  12. #12
    Registered User
    Join Date
    May 2019
    Posts
    214
    @cooper1200, @laserlight's point is demonstrated most clearly by experience where the debugger shows in one configuration that such code might work as you expect, but then a change in configuration breaks it.

    All of us this side of a few years' experience see it happen, followed by a facepalm.

  13. #13
    Registered User I C everything's Avatar
    Join Date
    Apr 2019
    Posts
    101
    Quote Originally Posted by Niccolo View Post
    @cooper1200, @laserlight's point is demonstrated most clearly by experience where the debugger shows in one configuration that such code might work as you expect, but then a change in configuration breaks it.

    All of us this side of a few years' experience see it happen, followed by a facepalm.
    you wrote about optimization,so I seen some compilers optimize to hard to follow and one exotic optimize to branchless code,like you mean full optimize arent foolproof,it suddenly breaks code,moving increments ????
    you tell me you can C,why dont you C your own bugs?

  14. #14
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    It is true that compiler can have bugs concerning optimisation, especially at high optimisation levels. However, examples like ++i + ++i are bugs with the program, not the compiler. They just happen to commonly manifest when compiler configuration such as optimisation levels change, but even if the bug doesn't manifest, it's still there. Maybe a compiler upgrade will break the code, etc.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  15. #15
    TEIAM - problem solved
    Join Date
    Apr 2012
    Location
    Melbourne Australia
    Posts
    1,907
    Stay away from undefined behaviour.

    I'd also caution the use of implementation defined behaviour...

    I've been caught before when work changed from one compiler to another.

    Everything that wasn't portable needed to be redone... It was a bad time...


    Now days I put a lot of emphasis on code being portable - And if it can't be portable, calling it from an external source so that it can be changed more easily - Utilizing an "Interface"
    Fact - Beethoven wrote his first symphony in C

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Difference??
    By aintgotnoname in forum C Programming
    Replies: 2
    Last Post: 11-25-2013, 10:54 PM
  2. What's the difference?
    By cuicle in forum C Programming
    Replies: 2
    Last Post: 09-30-2011, 01:41 PM
  3. Difference between C and C++
    By musicman in forum C Programming
    Replies: 8
    Last Post: 06-09-2011, 10:11 PM
  4. Is there a difference between...
    By jimbo_1 in forum C Programming
    Replies: 6
    Last Post: 03-25-2011, 05:29 PM
  5. Difference b/w int* p1 and int *p1
    By pprabhakar in forum C Programming
    Replies: 16
    Last Post: 08-21-2005, 05:27 AM

Tags for this Thread