Learn how easy it is to sync an existing GitHub or Google Code repo to a SourceForge project! See Demo

Close

Bug or not? Complement extends datatype

2010-03-17
2013-03-12
  • A small test app for 8051, SDCC v2.9.0:

    volatile unsigned char a = 0xf0;
    volatile unsigned char b = 0x0f;
    char main()
    {
      if (a == ~b)
      {
        return 0xaa;
      }
      return 0xbb;
    }
    

    Is compiled to:

    ...
    ;   D:\bug\main.c:6: if (a == ~b)
        mov r2,_b
        mov r3,#0x00
        mov a,r2
        cpl a
        mov r2,a
        mov a,r3
        cpl a
        mov r3,a
        mov r4,_a
        mov r5,#0x00
        mov a,r4
        cjne    a,ar2,00102$
        mov a,r5
        cjne    a,ar3,00102$
        C$main.c$8$2$2 ==.
    ;   D:\bug\main.c:8: return 0xaa;
        mov dpl,#0xAA
        C$main.c$10$1$1 ==.
    ;   D:\bug\main.c:10: return 0xbb;
        C$main.c$11$1$1 ==.
        XG$main$0$0 ==.
        ret
    00102$:
        mov dpl,#0xBB
        ret
    ...
    

    The comparison fails and 0xAA is returned, because
    both sides of the comparison are extended to 16 bits
    (int).  And 0x00f0 is obviously not equal to 0xfff0.

    I assume this is due to the complement operator.
    Is this correct behavior? I did not expect an implicit
    cast here.

    Regards,
    Andreas

     
  • Erik Petrich
    Erik Petrich
    2010-03-17

    Yes, this is correct. ISO/IEC 9899:1999 section 6.5.3.3 "Unary arithmetic operators" paragraph 4 states: "The result of the ~ operator is the bitwise complement of its (promoted) operand (that is, each bit in the result is set if and only if the corresponding bit in the converted operand is not set). The integer promotions are performed on the operand, and the result has the promoted type. If the promoted type is an unsigned type, the expression ~E is equivalent to the maximum value representable in that type minus E." Parenthetical expressions are part of the original.

    Informally, the standard generally says that C operators promote integer types to at least an int before applying the operator, which in turn will cause the operator result to be at least an int. If you need the result to be a smaller type, you will need to add an explicit cast or assignment:

      if (a == (unsigned char)~b)

    or

      b = ~b;
      if (a == b)

    (although, of course, this second example has the side effect of changing b)

     
  • Thank you for your quit response. I went for the explicit-cast solution. I wasn't aware that complement does lead to a type promotion, too. Now I'll be more careful.

     
  • That should read "quick response"… typo…