#1
  1. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    May 2013
    Posts
    36
    Rep Power
    2

    Unary operator precedence


    I'm wondering about operator precedence in a situation like *pointer++, where the increment operator is R->L, while the indirection operator has L->R precedence. Though the above example is straightforward, there might be situations where one would have to consider which operator would have precedence, and hope that someone could answer this question.
  2. #2
  3. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,254
    Rep Power
    2222
    C++ Operator Precedence. It's the same for C. Well defined.
  4. #3
  5. Contributing User

    Join Date
    Aug 2003
    Location
    UK
    Posts
    5,117
    Rep Power
    1803
    You are confusing associativity for precedence. Postfix -- and ++ are both of a higher precedence order than than the * dereference operator, so there is no ambiguity.

    That said, if you have to ask, don't do it!
    Code:
    p++ ;
    x = *p ;
    is always clearer than
    Code:
    x = *p++ ;
    and will most likely generate the same instruction sequence.
  6. #4
  7. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    May 2013
    Posts
    36
    Rep Power
    2
    Originally Posted by clifford
    You are confusing associativity for precedence. Postfix -- and ++ are both of a higher precedence order than than the * dereference operator, so there is no ambiguity.

    That said, if you have to ask, don't do it!
    Code:
    p++ ;
    x = *p ;
    is always clearer than
    Code:
    x = *p++ ;
    and will most likely generate the same instruction sequence.
    Response appreciated, and all very clear, except for the last phrase. Why do you qualify "most likely" generate the same instruction sequence? Are there exceptions?
  8. #5
  9. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,254
    Rep Power
    2222
    The actual instructions generated depend on each individual compiler. There's no requirement that all compilers generate the same sequence of instructions, but rather just that what they all do generate all produce the same results when they are executed.

    That is, of course, ignoring differences from different target processors with different instruction sets as well as the actual instructions available in the various instruction sets.

    It is very unreasonable to expect all compilers on all hardware platforms to all produce the exact same sequence of instructions.
  10. #6
  11. Banned ;)
    Devshed Supreme Being (6500+ posts)

    Join Date
    Nov 2001
    Location
    Woodland Hills, Los Angeles County, California, USA
    Posts
    9,643
    Rep Power
    4248
    Originally Posted by atlantis43
    Response appreciated, and all very clear, except for the last phrase. Why do you qualify "most likely" generate the same instruction sequence? Are there exceptions?
    Some compilers may have better optimization than others and even the same compiler may generate slightly different code depending on the optimization options you give it. Say you have this code:
    Code:
    p++;
    x = *p;
    A compiler with no optimization may generate code like this (I'm using pseudo machine code here):
    Code:
    ;; line 1
        1.1 Get value from the address of p into a machine register A
        1.2 Increment value of the register A
        1.3 Put the value contained in register A back into the address of p
    ;; line 2
        2.1 Get value from the address of p into a machine register A
        2.2 Go to the address that is in the machine register A and get the value from there into another register B
        2.3 Put the value of second register B back into the address of x
    A good optimizing compiler may notice that the result of the first statement is being used in the second statement. Therefore step 2.1 is unnecessary because the register A already contains the value of p from steps 1.2 and 1.3. Hence it may not generate the code for step 2.1 in the final code.

    Now if you wrote x = *p++; instead, a non optimizing compiler would generate slightly less code (i.e. steps 1.1, 1.2, 1.3, 2.2, 2.3) whereas an optimizing compiler may generate the same code whether you wrote x = *p++; or p++; x = *p;

    Of course, to do this optimization, an optimizing compiler has to go back through the code that it generated and remove the unnecessary steps, which means it takes a little longer to compile the code (this specific optimization falls under the class of "peephole optimization"). Many compilers have "optimization level" settings where you can tell a compiler how much optimization it should do and depending on the setting of the optimization level, the same compiler could generate different machine code for the same C code.
    Up the Irons
    What Would Jimi Do? Smash amps. Burn guitar. Take the groupies home.
    "Death Before Dishonour, my Friends!!" - Bruce D ickinson, Iron Maiden Aug 20, 2005 @ OzzFest
    Down with Sharon Osbourne

    "I wouldn't hire a butcher to fix my car. I also wouldn't hire a marketing firm to build my website." - Nilpo
  12. #7
  13. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    May 2013
    Posts
    36
    Rep Power
    2
    Originally Posted by Scorpions4ever
    Some compilers may have better optimization than others and even the same compiler may generate slightly different code depending on the optimization options you give it. Say you have this code:
    Code:
    p++;
    x = *p;
    A compiler with no optimization may generate code like this (I'm using pseudo machine code here):
    Code:
    ;; line 1
        1.1 Get value from the address of p into a machine register A
        1.2 Increment value of the register A
        1.3 Put the value contained in register A back into the address of p
    ;; line 2
        2.1 Get value from the address of p into a machine register A
        2.2 Go to the address that is in the machine register A and get the value from there into another register B
        2.3 Put the value of second register B back into the address of x
    A good optimizing compiler may notice that the result of the first statement is being used in the second statement. Therefore step 2.1 is unnecessary because the register A already contains the value of p from steps 1.2 and 1.3. Hence it may not generate the code for step 2.1 in the final code.

    Now if you wrote x = *p++; instead, a non optimizing compiler would generate slightly less code (i.e. steps 1.1, 1.2, 1.3, 2.2, 2.3) whereas an optimizing compiler may generate the same code whether you wrote x = *p++; or p++; x = *p;

    Of course, to do this optimization, an optimizing compiler has to go back through the code that it generated and remove the unnecessary steps, which means it takes a little longer to compile the code (this specific optimization falls under the class of "peephole optimization"). Many compilers have "optimization level" settings where you can tell a compiler how much optimization it should do and depending on the setting of the optimization level, the same compiler could generate different machine code for the same C code.
    Thanks for brief introduction to compilers & why they differ. There probably are such 'settings' available on my own compiler (a particularly picky one, which, as set, only gives 'errors' but no 'warnings', and refuses to compile anything with 'errors' present). But for now, I'm just trying to learn C.
  14. #8
  15. Contributing User

    Join Date
    Aug 2003
    Location
    UK
    Posts
    5,117
    Rep Power
    1803
    Originally Posted by atlantis43
    Why do you qualify "most likely" generate the same instruction sequence? Are there exceptions?
    The compiler has to parse the code and generate semantically correct machine code.

    There may be more than one sequence of instructions that will achieve the same result, and given different but semantically identical input, the compiler could conceivably generate different code. That is down to the compiler implementation. The point is that it is possible to have the same sequence of machine instructions for both, and a good compiler would generate identical optimal code in both cases. Even a poor compiler might find it hard to generate a different sequence from that simple example.
  16. #9
  17. Contributing User

    Join Date
    Aug 2003
    Location
    UK
    Posts
    5,117
    Rep Power
    1803
    Originally Posted by Scorpions4ever
    Now if you wrote x = *p++; instead, a non optimizing compiler would generate slightly less code (i.e. steps 1.1, 1.2, 1.3, 2.2, 2.3)
    I think in this case even non-optimising compilation would likely generate the same code since only one of the statements modifies p and only one deferences it and there is no reordering necessary. Most compilers will not move a value to memory only to load the same value into the same register immediately after. A good compiler will apply simple idiomatic optimisations such as this so long as they do not affect the debug experience - i.e. each source statement maps to specific sequence of machine code in the same order as the original source.

IMN logo majestic logo threadwatch logo seochat tools logo