value of the constant expression 1<<(1?1:1) < 0x9999

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Francois Grieu

    value of the constant expression 1<<(1?1:1) < 0x9999

    Hello,

    one of my C compiler (Keil C51) evaluates the constant expression
    1<<(1?1:1) < 0x9999
    to the value 1.

    // this returns 0, much to my surprise
    unsigned char bug4_a(void)
    {
    return 1<<(1?1:1) < 0x9999;
    }

    Can this find a satisfactory explanation under some definition of the
    C language ?


    Note: I still get 0 for

    return 1<<(1?1:1) < (unsigned)0x999 9;

    return 1<<(unsigned char)(1?1:1) < 0x9999;

    but I get 1 (as I expect) for

    return 1<<(1) < 0x9999;

    return (unsigned)1<<(1 ?1:1) < 0x9999;

    return 1u<<(1?1:1) < 0x9999;

    return 1<<(1?1:1) < 0x7777;

    return 1<<(1?1:1) == 2;

    #if 1<<(1?1:1) < 0x9999
    return 1;
    #else
    return 0;

    TIA,

    Francois Grieu
  • Peter Nilsson

    #2
    Re: value of the constant expression 1&lt;&lt;(1?1:1 ) &lt; 0x9999

    Francois Grieu wrote:
    Hello,
    >
    one of my C compiler (Keil C51) evaluates the constant expression
    1<<(1?1:1) < 0x9999
    to the value 1.
    Correct...

    1 << (1?1:1) < 0x9999
    (1 << (1?1:1)) < 0x9999
    (1 << 1) < 0x9999
    2 < 0x9999
    1
    // this returns 0, much to my surprise
    unsigned char bug4_a(void)
    {
    return 1<<(1?1:1) < 0x9999;
    }
    >
    Can this find a satisfactory explanation under some definition of the
    C language ?
    No.
    Note: I still get 0 for
    >
    return 1<<(1?1:1) < (unsigned)0x999 9;
    >
    return 1<<(unsigned char)(1?1:1) < 0x9999;
    Integer promotion must be applied, but it is incidental. They
    should all return 1 on a conforming implementation.

    --
    Peter

    Comment

    • Keith Thompson

      #3
      Re: value of the constant expression 1&lt;&lt;(1?1:1 ) &lt; 0x9999

      Francois Grieu <fgrieu@gmail.c omwrites:
      one of my C compiler (Keil C51) evaluates the constant expression
      1<<(1?1:1) < 0x9999
      to the value 1.
      >
      // this returns 0, much to my surprise
      unsigned char bug4_a(void)
      {
      return 1<<(1?1:1) < 0x9999;
      }
      >
      Can this find a satisfactory explanation under some definition of the
      C language ?
      The behavior is inconsistent with the C standard. (If Keil C51 claims
      to conform, it's a bug; if it doesn't, it may or may not be a bug,
      depending on what, if anything, its documentation says).

      I'll assume that types int and unsigned int are 16 bits.

      1<<(1?1:1) has the value 2 and is of type int.

      0x9999 has the value 39321 and is of type unsigned int.

      The "usual arithmetic conversions" are applied to the operands of "<".
      This converts the left operand, 2, from int to unsigned int.

      So the expression 1<<(1?1:1) < 0x9999 is equivalent to 1U < 39321U,
      which yields the int value 1. The return statement converts this to
      unsigned char, yielding (unsigned char)1.

      My guess is that a bug in the compiler is causing it to do the "usual
      arithmetic conversions" incorrectly in this case. It's probably
      converting the right operand to signed int rather than converting the
      left operand to unsigned int, changing the comparison:
      (int)2 < (unsigned)39321
      to
      (int)2 < (int)-26215
      which yields 0.

      Try replacing 0x9999 with 0x7fff and 0x8000 and see what happens.

      [snip]

      --
      Keith Thompson (The_Other_Keit h) <kst-u@mib.org>
      Nokia
      "We must do something. This is something. Therefore, we must do this."
      -- Antony Jay and Jonathan Lynn, "Yes Minister"

      Comment

      • Peter Nilsson

        #4
        Re: value of the constant expression 1&lt;&lt;(1?1:1 ) &lt; 0x9999

        Keith Thompson wrote:
        ...
        I'll assume that types int and unsigned int are 16 bits.
        >
        1<<(1?1:1) has the value 2 and is of type int.
        >
        0x9999 has the value 39321 and is of type unsigned int.
        >
        The "usual arithmetic conversions" are applied to the operands
        of "<". This converts the left operand, 2, from int to unsigned int.
        >
        So the expression 1<<(1?1:1) < 0x9999 is equivalent to
        1U < 39321U,
        ITYM: 2U < 39321U

        --
        Peter

        Comment

        • Keith Thompson

          #5
          Re: value of the constant expression 1&lt;&lt;(1?1:1 ) &lt; 0x9999

          Peter Nilsson <airia@acay.com .auwrites:
          Keith Thompson wrote:
          >...
          >I'll assume that types int and unsigned int are 16 bits.
          >>
          >1<<(1?1:1) has the value 2 and is of type int.
          >>
          >0x9999 has the value 39321 and is of type unsigned int.
          >>
          >The "usual arithmetic conversions" are applied to the operands
          >of "<". This converts the left operand, 2, from int to unsigned int.
          >>
          >So the expression 1<<(1?1:1) < 0x9999 is equivalent to
          >1U < 39321U,
          >
          ITYM: 2U < 39321U
          Yes, thanks.

          --
          Keith Thompson (The_Other_Keit h) <kst-u@mib.org>
          Nokia
          "We must do something. This is something. Therefore, we must do this."
          -- Antony Jay and Jonathan Lynn, "Yes Minister"

          Comment

          • Francois Grieu

            #6
            Re: value of the constant expression 1&lt;&lt;(1?1:1 ) &lt; 0x9999

            I am as tired as my cimpiler. Should have said

            one of my C compiler (Keil C51) evaluates the constant expression
            1<<(1?1:1) < 0x9999
            to the value 0.

            Thje rest was hopefully correct.

            Francois Grieu

            Comment

            • Francois Grieu

              #7
              Re: value of the constant expression 1&lt;&lt;(1?1:1 ) &lt; 0x9999

              On 30 avr, 00:53, Keith Thompson <ks...@mib.orgw rote:
              Francois Grieu <fgr...@gmail.c omwrites:
              one of my C compiler (Keil C51) evaluates the constant expression
              1<<(1?1:1) < 0x9999
              to the value 0 [typo fixed]
              >
              // this returns 0, much to my surprise
              unsigned char bug4_a(void)
              {
              return 1<<(1?1:1) < 0x9999;
              }
              >
              Can this find a satisfactory explanation under some definition of the
              C language ?
              >
              The behavior is inconsistent with the C standard. (If Keil C51 claims
              to conform, it's a bug; if it doesn't, it may or may not be a bug,
              depending on what, if anything, its documentation says).
              It is supposed to be "a complete implementation of the ANSI standard
              for the C language", without mention of version, so I guess C89. There
              is a section on "Difference s from ANSI C", with no relevant entries.
              I'll assume that types int and unsigned int are 16 bits.
              Yes.
              1<<(1?1:1) has the value 2 and is of type int.
              Yes. 1 is signed, thus 1<<.. is.
              0x9999 has the value 39321 and is of type unsigned int.
              Yes.
              The "usual arithmetic conversions" are applied to the operands of "<".
              This converts the left operand, 2, from int to unsigned int.
              Thanks. That was the part I'm never sure in on standards before C99.
              So the expression 1<<(1?1:1) < 0x9999 is equivalent to 1U < 39321U,
              which yields the int value 1. The return statement converts this to
              unsigned char, yielding (unsigned char)1.
              >
              My guess is that a bug in the compiler is causing it to do the "usual
              arithmetic conversions" incorrectly in this case. It's probably
              converting the right operand to signed int rather than converting the
              left operand to unsigned int, changing the comparison:
              (int)2 < (unsigned)39321
              to
              (int)2 < (int)-26215
              which yields 0.
              Yes. However the fun thing is that the problem occurs only if
              the ?: operator is used.
              (int)2 < (unsigned)39321 gives 1
              1<<(1?1:1)<3932 1 gives 0
              1<<1 <39321 gives 1
              (1?2:2) <39321 gives 0
              Try replacing 0x9999 with 0x7fff and 0x8000 and see what happens.
              Problem disapears.


              Thanks, we found a compiler bug. I'll report it.

              Francois Grieu

              Comment

              • Francois Grieu

                #8
                Re: value of the constant expression 1&lt;&lt;(1?1:1 ) &lt; 0x9999

                Try replacing 0x9999 with 0x7fff and 0x8000 and see what happens.

                Problem disapears for 0x7fff but remain with 0x8000.

                Comment

                Working...