Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C bit field variables are printing unexpected values

Tags:

c

bit

struct m

{
   int parent:3;

   int child:3;

   int mother:2;
};

void main()
{

   struct m son={2,-6,5};

   printf("%d %d %d",son.parent,son.child,son.mother);
}

Can anybody please help in telling why the output of the program is 2 2 1 ?

like image 746
Keerthi Ranganath Avatar asked Jan 15 '13 11:01

Keerthi Ranganath


People also ask

Should you use bit fields in C?

Bit Fields in C Language Since structures and unions are user-defined data types in C, the user has an idea of how much memory will they occupy. Accordingly, by the implementation of bit fields, memory management becomes easy and efficient.

What is bit fields in C?

Both C and C++ allow integer members to be stored into memory spaces smaller than the compiler would ordinarily allow. These space-saving structure members are called bit fields, and their width in bits can be explicitly declared.

Is array of bit fields allowed?

Arrays of bit fields, pointers to bit fields, and functions returning bit fields are not allowed. The optional declarator names the bit field. Bit fields can only be declared as part of a structure. The address-of operator (&) cannot be applied to bit-field components.

What are the limitations of bit field usage in embedded systems?

As we saw earlier, bit fields result in non-portable code. Also, the bit field length has a high dependency on word size. 2. Reading (using scanf) and using pointers on bit fields is not possible due to non-addressability.


2 Answers

Taking out all but the significant bits for the fields shown:

parent: 3 bits (1-sign bit + 2 more), value 010, result 2
child:  3 bits (1-sign bit + 2 more), value 010, result 2
mother: 2 bits (1 sign bit + 1 more), value  01, result 1

Details

It bears pointing out that your structure fields are declared as int bit-field values. By C99-§6.7.2,2, the following types are all equivalent: int, signed, or signed int. Therefore, your structure fields are signed. By C99-§6.2.6.2,2, one of your bits shall be consumed in representing the "sign" of the variable (negative or positive). Further, the same section states that excluding the sign-bit, the remaining bits representation must correspond to an associated unsigned type of the remaining bit-count. C99-§6.7.2,1 clearly defines how each of these bits represents a power of 2. Therefore, the only bit that is normally used as the sign-bit is the most significant bit (its the only one that is left, but I'm quite sure if this is an inaccurate interpretation of the standard I'll hear about it in due time). That you are assigning a negative number as one of your test values used for your sample suggests you may be aware of this, but many people newly exposed to bit fields are not. Thus, it bears noting.

The following sections of the C99 standard are referenced in the remainder of this answer. The first deals with promotions to different types, the next the valuation and potential value-change (if any). The last is important in understanding how a bit-fields int-type is determined.

C99-§6.3.1.1: Boolean, characters, and integers

2: 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. These are called the integer promotions. All other types are unchanged by the integer promotions.

C99-§6.3.1.3 Signed and unsigned integers

  1. When a value with integer type is converted to another integer type other than _Bool, if the value can be represented by the new type, it is unchanged.
  2. Otherwise, if the new type is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type.
  3. Otherwise, the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised.

C99-§6.7.2.1 Structure and Union Specifiers

10: A bit-field is interpreted as having a signed or unsigned integer type consisting of the specified number of bits. If the value 0 or 1 is stored into a nonzero-width bit-field of type _Bool, the value of the bit-field shall compare equal to the value stored; a _Bool bit-field has the semantics of a _Bool.

Consider the regular int bit representation of your test values. The following are on a 32-bit int implementation:

value : s  bits 
    2 : 0  0000000 00000000 00000000 00000010   <== note bottom three bits
   -6 : 1  1111111 11111111 11111111 11111010   <== note bottom three bits
    5 : 0  0000000 00000000 00000000 00000101   <== note bottom two bits

Walking through each of these, applying the requirements from the standard references above.

int parent:3 :The first field is a 3-bit signed int, and is being assigned the decimal value 2. Does the rvalue type, int, encompass the lvalue type, int:3? Yes, so the types are good. Does the value 2 fit within the range of the lvalue type? Well, 2 can easily fit in an int:3, so no value mucking is required either. The first field works fine.

int child:3: The second field is also a 3-bit signed int, this time being assigned the decimal value -6. Once again, does the rvalue type (int) fully-encompass the lvalue type (int:3)? Yes, so again the types are fine. However, the minimum bit-count require to represent -6, a signed value, is 4 bits. (1010), accounting for the most signnificant bit as the sign-bit. Therefore the value -6 is out of range of the allowable storage of a 3-bit signed bit-field. Therefore, the result is implementation-defined per §6.3.1.3-3.

int mother:2 The final field is a 2-bit signed int, this time being assigned the decimal value 5. Once again, does the rvalue type (int) fully-encompass the lvalue type (int:2)? Yes, so again the types are fine. However, once again we're faced with a value that cannot fit within the target-type. The minimum bit-count need for representing a signed positive 5 is four: (0101). We only have two to work with. Therefore, the result is once again implementation-defined per §6.3.1.3-3.

Therefore, if I take this correctly, the implementation in this case simply hacks off all but the required bits needed to store fill the declared bit depth. And the results of that hackery is what you now have. 2 2 1

Note

It is entirely possible I flipped the order of the promotion incorrectly (it is easy for me to get lost in the standard, as I am dyslexic and flip things in my head periodically). If that is the case I would ask anyone with a stronger interpretation of the standard please point this out to me an I will address the answer accordingly.

like image 200
WhozCraig Avatar answered Oct 11 '22 07:10

WhozCraig


The bit fields size for child and mother are too small to contain the constant values you are assigning to them and they're overflowing.

like image 39
Eran Avatar answered Oct 11 '22 07:10

Eran