0

In the code below:

#include <stdio.h>

struct
{
  int Member1 : 3;
  int Member2 : 1;
}d2;

int main(){

  d2.Member1 = 7;
  printf("%d\n",d2.Member1);

  return 0;

}

The result is -1, why is it? What's the binary value of the d2 now?

user3289218
  • 87
  • 1
  • 5

4 Answers4

4

Because you did not specify if d2.Member1 is signed or unsigned, it is up to the compiler and apparently the one you are using chose to make it a signed field, and therefore has the range -4 to 3. 7 is out of range, so it overflows.

Make d2.Member1 an unsigned int instead, and use %u in your printf() call instead of %d. (Demo.)

cdhowie
  • 158,093
  • 24
  • 286
  • 300
  • 1
    nit pick, but I wouldn't call it overflow if an operation didn't occur, but that's right. – kenny Sep 09 '14 at 20:48
  • `u` conversion specifier requires an `unsigned int` so you need to cast the argument to `unsigned int` here. Moreover it is implementation defined if `d2.Member1` is a signed or an unsigned bit-field. – ouah Sep 09 '14 at 20:49
  • @kenny Technically assignment is an operation, no? – cdhowie Sep 09 '14 at 20:52
  • @cdhowie: A bit-field wiuth value range that fits into `int` will be promoted to `int`, even if the original bit-field type is `unsigned int`. For this reason, `%d` in `printf` is actually more appropriate in this case. To use `%u` one'd have to explicitly cast the argument, e.g. `(unsigned) d2.Member1`. – AnT stands with Russia Sep 09 '14 at 21:04
  • regardless of what you decide to call it, assigning an out-of-range value to a signed integral type causes implementation-defined behaviour (which may raise a signal). So your compiler should document what happens here, although good luck in finding that documentation! – M.M Sep 09 '14 at 21:14
  • Hi, I understand that it is signed, but I don't understand why it becomes -1. The binary value of signed -1 is 1111, and 7 is 111, and there are only 3 bits to be used, how it became -1? – user3289218 Sep 09 '14 at 21:19
  • 1
    @user3289218 for a 3 bit int number 111 is -1, in your example 1111 it would be a 4 bit field. – kenny Sep 09 '14 at 21:24
  • @user3289218: `-1` is `1111`? Where did `1111` come from? Why not `11111` or `111111`? – AnT stands with Russia Sep 10 '14 at 00:25
1

You assign binary 111 to 3-bit value. Since you declared the field as signed, this means 3-bit long '-1'. When you request an integer value, it is left-padded with the leftmost bit to preserve the sign. If you expect the output 7, declare your bit field as unsigned Member1: 3. Expansion to full integer will pad the missing MSB with 0 rather than the leftmost bit.

ArunasR
  • 1,907
  • 1
  • 14
  • 15
1

To quote the C90 standard:

A bit-field shall have a type that is a qualified or unqualified version of one of int, unsigned int, or signed int. Whether the high-order bit position of a (possibly qualified) “plain” int bit-field is treated as a sign bit is implementation-defined. A bit-field is interpreted as an integral type consisting of the specified number of bits.

So it's -1 because you didn't explicitly specify it as unsigned and, in the C implementation you're using, the high-order bit position of a "plain" int bit-field is treated as a sign bit. You have a 3-bit bit-field, all the bits of which are 1, so that's -1.

1

C language does not define whether an int bit-field is signed or unsigned. The decision is left to implementation. For this reason, it is typically not a good idea to ever declare int bit-fields. Use either explicitly signed int or explicitly unsigned int bit-fields, depending on what you need. (It is one area of C language where int does not necessarily mean signed int.)

In your case your 3-bit int bit-field happened to be signed. The value range of such bit-field is [-4, 3], assuming 2's-complement representation. You attempted to assign 7 to it, causing overflow. What happens in case of signed integer overflow on assignment is implementation-defined. You ended up with -1 apparently.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765