Comparison of Unsigned bit field value with signed values

(move my remark as an answer)

gcc promotes s.bit to an int, so (negVal > s.bit) does (-3 > 0) valuing 0

See Should bit-fields less than int in size be the subject of integral promotion? but your question is not a duplicate of it.


(negVal > p) returns 1 because negVal is promoted to unsigned producing a big value, see Signed/unsigned comparisons


For illustration, the following uses a 32-bit int and a 32-bit unsigned int.

In negVal > p:

  • negVal is an int with value −3.
  • p is an unsigned int with value 123.
  • C 2018 6.5.8 3, which is discusses > and the other relational operators, tells us that the usual arithmetic conversions are performed on the operands.
  • 6.3.1.8 1 defines the usual arithmetic conversions. For integer types, the first step of the usual arithmetic conversions is to perform the integer promotions on each operand.
  • 6.3.1.1 2 defines the integer promotions. int, unsigned int, and integer types wider than these are unchanged. For other integer types, it says: ”If an int can represent all values of the original type (as restricted by the width, for a bit-field), the value is converted to an int; otherwise, it is converted to an unsigned int.”
  • Since negVal is an int, it is unchanged by the integer promotions.
  • Since p is an unsigned int, it is unchanged by the integer promotions.
  • The next step in the usual arithmetic conversions is to convert one operand to the type of the other. For int and unsigned int, the int is converted to unsigned int.
  • Converting the int −3 to unsigned int results in 4,294,967,293. (The conversion is defined to add or subtracting UINT_MAX + 1, which is 4,294,967,296, to the value as many times as necessary to bring it in range. This is equivalent to “wrapping” modulo 4,294,967,296 or to reinterpreting the two’s complement representation of −3 as an unsigned int.)
  • After the conversions, the expression negVal > p has become 4294967293u > 123u.
  • This comparison is true, so the result is 1.

In negVal > s.bit:

  • negVal is an int with value −3.
  • s.bit is a one-bit bit-field with value 0.
  • As above, the usual arithmetic conversions are performed on the operands.
  • As above, the first step of the usual arithmetic conversions is to perform the integer promotions on each operand.
  • Since negVal is an int, it is unchanged by the integer promotions.
  • Since s.bit is a bit-field narrower than an int, it will be converted by the integer promotions. This one-bit bit-field can represent either 0 or 1. Both of these can be represented by an int, and therefore the rule “If an int can represent all values of the original type (as restricted by the width, for a bit-field), the value is converted to an int” applies.
  • Converting 0 to int results in 0.
  • The next step in the usual arithmetic conversions would be to convert one operand to the type of the other. Since both operands are now int, no conversion is needed.
  • After the conversions, the expression negVal > s.bit has become -3 > 0.
  • This comparison is false, so the result is 0.

Tags:

C

Bit Fields