This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

C Problem?

unsigned char x=1;
x=(x++)<<3;

Using uVision 6.12
Gives answer of 8
It shifts binary 1 left and doesn't increment.
(even when optimization set to level 0)

Using Micorsoft C++ 6.0
Gives answer of 9
It shifts binary 1 left then increments.


I was a little confused with both answers because I was thought that
the increment would happen first because of the ( ) around x++ then
shift left three giving 16 but that's not the case.

This gives me 16 in both Keil and MS.
x=(++x)<<3; works it gives 16


  • Keil does have some problems with the pre- and post- increment/decrement operators when used within a more complicated expression.

    However, the value of the expression "x++" is x; the increment is not done until after the expression is evaluated - hence post increment!

    So

    (x++)<<3
    is equivalent to
    (x)<<3; x += 1
    and it seems that MSVC has the "right" answer.

    This kind of thing is often quoted to show the problems of macros!


  • Between consecutive "sequence points", an object's value can be modified only once by an expression. The only "sequence point" in your line of code is the ";". This means x is modified twice. Once by the =, and once by the ++. This code has no well defined meaning. It is not surprising that different implementations gave different answers.

  • Since this equation produces undefined behavior, there is no right answer IMHO. See:

    http://www.eskimo.com/~scs/C-faq/q3.3.html


    I suggest:
    x = x + 1 << 3;
    and remember that + happens before <<.

    :-)

    - Mark

  • To Keil Discussion Forum site:

    Add the following suggestion to your "Tips for Posting Measages".

    If you type an URL like

    <pre>TheUrl</pre>

    then add a space before the </pre>.

    If you don't, one can not follow the hyperlink (using IE5.5) by clicking on it.

  • Actually, there is no need to use the &ltpre&gt and &lt/pre&gt tags for URLs at all - the forum automatically makes URLs clickable (as it says in the Tips).

    It seems that it's this automatic conversion to a link which has gone wrong - it's caught the closing &lt/pre&gt tag inside the closing &lt/a&gt link tag!
    So yes, a space (or newline?) before the &lt/pre&gt would probably have fixed it.

  • Sorry about that, I didn't mean to use the pre tag at all.

    - Mark

  • >Keil does have some problems with the pre- and
    >post- increment/decrement operators when used
    >within a more complicated expression

    Which problems your take in mind ?



    >(x++)<<3
    >is equivalent to

    >(x)<<3; x += 1
    >and it seems that MSVC has the "right" >answer.


    This is not exactly the same as original qiestion:

    unsigned char x = 1;
    x=(x++) << 3;
    

    is equivalent to

    unsigned char x = 1;
    unsigned char tmp;
    
    tmp = x;          // get old value of 'x'
    x   = x + 1;      // x++
    x   = (tmp << 3); // Assign('=') have lowest priority
    
    

    So, right answer is 'x==8' after all.



  • See "The C Programming Language", second edition, section 2.12. K&R have quite a lot to say about this sort of problem including:

    "One unhappy situation is typified by the statement

    a[i] = i++;
    
    The question is whether the subscript is the old value of i or the new. Compilers can interpret this in different ways and generate different answers depending up their interpretation...."

  • Please see

    http://www.eskimo.com/~scs/C-faq/q3.3.html

    x = (x++) << 3;
    not only are the parens useless since ++ is much higher precedence than << but the resultant value assigned to x is up to the implementation (compiler) you are using. This sort of equation should be written as
    x = x + 1 << 3;
    Let the compiler figure out that +1 means INC.

    Regards,

    - Mark

  • Mark,
    thanks for good point:
    http://www.eskimo.com/~scs/C-faq/q3.3.html

    http://www.eskimo.com/~scs/C-faq/top.html

    It is a good place to understand why I intuitively avoid some
    ambiguous C-constructions :)

    On the other side, this is a 'style' quiestion.
    For example, in your case I always write as

    x = (x + 1) << 3;
    
    despite that "no need" parens,
    just to produce evident readability.


    But if we return to original question,
    unsigned char x = 1;
    x = (x++) << 3;
    
    I think that in this case Keil-implementation "more suitable" :),
    because MSVC result '9'
    (accordingly author's original message)
    can be explained only if suppose that 'x++' evaluated after assigning '8' to x.

    As I remember, '=' operation in C:
      LVALUE = EXPRESSION
    
    calculated from right to left.

    I think, this means that
    at first
    EXPRESSION should be COMPLETELY evaluated (with all nested operations, EVEN side-effect operations such as function calls),
    then
    result of expression saved to place
    pointed by LVALUE.


    This is just my common-sense opinion :)

  • unsigned char x = 1;
    x = (x++) << 3;
    "MSVC result '9' ... can be explained only if suppose that 'x++' evaluated after assigning '8' to x."

    Which is what I'd expect from a post increment:

    "x++" means "take the value of x and then, when you've done with it, increment x by one"

    In this case, "when you've done with it" means, "when you've shifted it"

    However, I agree with the consensus that this is ambiguous and best avoided!

  • This thread is well and truly dead, but I've found another situation where an ambiguity similar to this can trip you up:

      a[b++] = c;
    

    The problem is not quite the same as that described above though; it only occurs when multithreading.

    C166 5.00 saves b+1 into b BEFORE assigning c to a[b]. What I found is that an ISR could interrupt this sequence and find b incremented, but the wrong data in a[b] (the assignment hadn't been completed).

  • Welcome to the wonderful club comprised of those bitten by race conditions. We'll get you your membership card tomorrow.

    In point of fact, there doesn't need to be an index in this expression to cause a problem. Essentially, if you have interrupt-driven code, you must imagine that any instruction that is not "atomic" (i.e. completed without interruption) can be stopped in the middle.

    Thus, something as simple as

    a = b;

    where a and b are 16-bit values and you're using, say, an 8051 can cause problems if they are modified in main code and used in an ISR or vice-versa.

  • This ambiguity is actually rather unrelated to the one discussed here earlier. The earlier examples had much more serious problems than yours --- they produced undefined behaviour, which means the compiler is allowed to explode the processor 123*pi hours after noon of the Tuesday following last year's Hallowe'en, if it so pleases.

    Your example is broken only because introduced an additional ingredient into the game: multiple (pseudo-)concurrent threads of control. C doesn't even try to address that type of problem in the language itself, beyond controlling access to individual objects via the volatile qualifier.