Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Comparison of Unsigned bit field value with signed values

Tags:

c

bit-fields

while writing the code I observe one thing in my code its related to the comparison of bit-field value with negative integers.

I have one structure member of unsigned of size one bit and one unsigned int. When I compare the negative value with unsigned int variable I am getting expected result as 1 but when I compare the structure member with the negative value I am getting the opposite result as 0.

#include <stdio.h>
struct S0
{
   unsigned int bit : 1;
};
struct S0 s;

int main (void) 
{
   int negVal = -3;
   unsigned int p = 123;
   printf ("%d\n", (negVal > p)); /*Result as 1 */
   printf ("%d\n", (negVal > s.bit));/*Result as 0 but expected 1 */
   return 0;
}

My doubt is if I compare the negative value with unsigned int then balancing will happen (implicit type casting). But if I compare structure member of unsigned int why implicit type casting is not happening. Correct me if I miss any basics of bit fields?

like image 889
goodman Avatar asked Feb 18 '19 07:02

goodman


2 Answers

(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

like image 96
bruno Avatar answered Sep 30 '22 13:09

bruno


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.
like image 41
Eric Postpischil Avatar answered Sep 30 '22 14:09

Eric Postpischil