-1

For about 3-4 hours and start reading about bit fields in C and I can't understand how they work. For example, I can't understand why the program has the output: -1, 2, -3

#include <stdio.h>

struct REGISTER {
    int bit1 : 1;
    int      : 2;
    int bit3 : 4;
    int bit4 : 4;
};

int main(void) {
    struct REGISTER bit = { 1, 2, 13 };
    printf("%d, %d, %d\n", bit.bit1, bit.bit3, bit.bit4);
    return 0;
}

Can someone give me an explanation? I tend to think that if I use unsigned in the struct then the output would be positive. But I don't know where that -3 comes from.

chqrlie
  • 131,814
  • 10
  • 121
  • 189
DaniVaja
  • 211
  • 1
  • 7

4 Answers4

3

Your compiler considers the type int of a bit field as the type signed int.

Consider the binary representation of initializers (it is enough to consider one byte)

1  -> 0b00000001
2  -> 0b00000010
13 -> 0b00001101

So the first bit-field having the width equal to 1 gets 1. For an integer with one bit this bit is the sign bit. So such a bit field can represent two values 0 and -1 (in the 2's complement representation).

The second initialized bit-field has the width equal to 4. So it stores the bit representation 0010 that is equal to 2.

The third initialized bit-field also has the width equal to 4. So its stored bit combination is equal to 1101. The most significant bit is the sign bit and it is set. So the bit-field contains a negative number. This number is equal to -3.

   1101 ( = -3 )
+
   0011 ( = 3 )
   ====
   0000 ( = 0 )
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • Your explanation for the observed behavior is correct but incomplete: technically, the initializer invokes implementation-defined behavior as 1) signedness is implementation defined and 2) in case `int` bit-fields are considered signed by the implementation, `1` and `13` are outside the range of values for the signed type they initialize. Using `unsigned int` is definitely a better choice for the OP. – chqrlie Sep 12 '20 at 10:33
  • @chqrlie I wrote in the very beginning that "Your compiler considers the type int of a bit field as the type signed int." – Vlad from Moscow Sep 12 '20 at 10:54
  • Yes, you alluded to implementation-defined behavior regarding the signedness issue. An explicit phrase would probably improve clarity. Implementation defined conversion is also an issue. Both issues are solved adequately by using `unsigned int` for the bit-field type for the `bit1` and `bit4`. – chqrlie Sep 12 '20 at 11:26
  • @chqrlie I hope your comment will be read by the author of the question.:) – Vlad from Moscow Sep 12 '20 at 11:32
2

It is implementation-defined whether an int bitfield is signed or unsigned, hence it is actually an error in any program where you care about the value - if you care for the value you will qualify it either as signed or unsigned.

Now, your compiler considers bitfields without specified signedness as signed. I.e. int bit4: 4 tells that that bit-field is 4 bits wide and signed.

13 cannot be represented in a signed 4-bit bitfield as the maximum value is 7, no matter the representation of negative numbers - 2's complement, 1's complement, sign-and-magnitude. An implementation-specified conversion will now occur: in your case the bit representation 1101 is stored as-is in the 2's complement signed bitfield, and it is considered as the 2's complement negative value -3.

Same happens for 1-bit signed bitfield: the one bit is the sign bit, hence there are only 2 possible values: 0 and -1 on two's complement systems. On one's complement system, or sign-and-magnitude, one-bit bitfield does not make any sense at all because it can only store 0 or a trap value.

If you want it to be able to store value 13, you will have to use at least 5 bits or use unsigned int: 4.

1

Please Dont use signed int in this operation. here that lead to minus results. if we use unsigned int,The output comes out to be negative

What happened behind is that the value 13 was stored in 4 bit signed integer which is equal to 1101. The MSB is a 1, so it’s a negative number and you need to calculate the 2’s complement of the binary number to get its actual value which is what is done internally. By calculating 2’s complement you will arrive at the value 0011 which is equivalent to decimal number 3 and since it was a negative number you get a -3.

#include <stdio.h>

struct REGISTER {

  unsigned int bit1: 1;
  unsigned int :2;
  unsigned int bit3: 4;

  unsigned int bit4: 4;
};

int main(void) {
  struct REGISTER bit={1,2,13};
  printf("%d, %d, %d\n", bit.bit1, bit.bit3, bit.bit4);
  return 0;
}

Here the output will be exactly 1,2,13

Thanks

Anandha
  • 47
  • 10
  • 1
    _if we use unsigned int,The output comes out to be negative_... Did you mean to say: _ if we use unsigned `int`,The output comes out to be negative_? – ryyker Sep 11 '20 at 18:18
0

It's pretty easy, you're initializing the bitfields as follows:

  1. 1 as bit length 1. That means the MSB is 1, which since the type is int is the sign bit. So the resulting value is -0-1 = -1.
  2. 2 as bit length 4. MSB (sign bit) is 0, so the result is positive, ie 2.
  3. 13 as bit length 4. In binary that is 1101, so the MSB is 1 (negative), so the resulting value is -2-1 = -3.

You can read more about two's complement (the format in which numbers are stored on Intel architectures) here. The short version is that negative numbers have MSB=1, and to calculate their value you take the negative of their not representation (without the sign bit) minus one.

Blindy
  • 65,249
  • 10
  • 91
  • 131