Structure with signed integer bit-fields resulting minus outputs - c

This is the C code with a struct.
#include <stdio.h>
#include <stdlib.h>
int main()
{
struct{
int a : 4;
unsigned int b : 3;
int c : 3;
} x;
x.a = 7;
x.b = 7;
x.c = 7;
printf("%d\n",x.a);
printf("%d\n",x.b);
printf("%d\n",x.c);
return 0;
}
In the above C program x.c has allocated 3 bits from memory but resulting an output result as -1. What is the reason for this?

data member c is defined as having type int (that is signed int in case of your compiler) and have only 3 bits to represent signed values. So the most significant bit is considered as the sign bit, 7 in the binary notation looks as
111
where the left-most bit is used as the sign bit due to the definition
int c : 3;
So this combination of bits means that the number is negative and equal to -1.
The maximum positive value that can be stored in this bit field is equal to 3
011
and the minimum negative value is equal to -4
100
Take into account that it is implementation defined whether a bit field defined as having type int will be interpretated as unsigned int or signed int. Your compiler consideres a bit field of type int as having type signed int
So it is better to explicitly specify either signed int or unsigned int for bit fields.
From the C Standard
...except that for bitfields, it is implementation-defined whether the
specifier int designates the same type as signed int or the same type
as unsigned int.

In two's complement, -1 is represented as 11111111......... {as many as number of bits }
When you assign 7, which is 111 in binary, the sign bit gets 1, and remaining bits get 1 and 1.
Now,
sign bit = 1 => number is negative
remaining bits = 11 => 1 in two's complement.
Hence the result is negative one
note: from the behavior, it appears your machine implements two's complement

The difference between an int and unsigned datatype is the significance of the sign bit. In the above code, you are using int for x.c with 3 bits to store the value 7, which in binary translates to 111. When you print the value in x.c, using %d, it is taken as the sign bit to be set. If you are on a little-endian machine and if you initialize it with any value higher than 4, you would be setting the sign bit and getting a result of two's complement as MAKZ said in his answer.
so
7 will print as -1, 6 will print as -2, 5 will print as -3, 4 will print as -4

Related

can't understand bit fields in C

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.
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 )
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.
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
It's pretty easy, you're initializing the bitfields as follows:
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 as bit length 4. MSB (sign bit) is 0, so the result is positive, ie 2.
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.

Signed and Unsigned program error

So today am learning about the signed and unsigned variables. So what i can make out is that signed can have positive, negative and zero values and unsigned can have only the positive values.
So to try this through code i wrote this program in c:
#include <stdio.h>
#include <stdlib.h>
void main()
{
int a=-10;
unsigned int x=-4;
printf("signed variable value is : %d\n Unsigned variable value is : %u",a,x);
}
SO as per my expectation output should be like this :
signed variable value is : -10
Unsigned variable value is : 4
But in reality it turned out to be like this:
signed variable value is : -10
Unsigned variable value is : 4294967292
Can any one explain this !!
When you assign a negative value into a unsigned int and print it using the format specifier %u, 2's complement of that number will be taken into consideration.
So that x become 2's complement of -4, ie 4294967292
A similar question is asked here
Assigning negative numbers to an unsigned int?
The way that unsigned variables work is that they wrap around past 0 (both going forward and back), treating 0 as congruent to 232 (on a 32-bit system). To see this, try the following program:
#include <stdio.h>
int main()
{
unsigned int test = 3;
for (int i = 0; i < 10; ++i)
{
test = test - 1;
printf("%u\n", test);
}
}
Output (on a 32-bit system):
2
1
0
4294967295
4294967294
4294967293
4294967292
4294967291
4294967290
4294967289
Back to your code. -4 is of course the same as 0 - 4 so what you have gotten is the fourth item past 0 on this list.
NB. Your code does not have any errors apart from void main
The unsigned variable doesn't take the absolute value for you.
Since you are putting a negative value in it, it casts the signed integer value (-4) to a 4 byte unsigned variable.
I am guessing the negative values are stored as 2's complement here. Therefore what you get as a -4 on a unsigned 4byte variable is in fact 2^32 -4 (one wrap around) : 4294967292

How does C store negative numbers in signed vs unsigned integers?

Here is the example:
#include <stdio.h>
int main()
{
int x=35;
int y=-35;
unsigned int z=35;
unsigned int p=-35;
signed int q=-35;
printf("Int(35d)=%d\n\
Int(-35d)=%d\n\
UInt(35u)=%u\n\
UInt(-35u)=%u\n\
UInt(-35d)=%d\n\
SInt(-35u)=%u\n",x,y,z,p,p,q);
return 0;
}
Output:
Int(35d)=35
Int(-35d)=-35
UInt(35u)=35
UInt(-35u)=4294967261
UInt(-35d)=-35
SInt(-35u)=4294967261
Does it really matter if I declare the value as signed or unsigned int? Because, C actually only cares about how I read the value from memory. Please help me understand this and I hope you prove me wrong.
Representation of signed integers is up to the underlying platform, not the C language itself. The language definition is mostly agnostic with regard to signed integer representations. Two's complement is probably the most common, but there are other representations such as one's complement and signed magnitude.
In a two's complement system, you negate a value by inverting the bits and adding 1. To get from 5 to -5, you'd do:
5 == 0101 => 1010 + 1 == 1011 == -5
To go from -5 back to 5, you follow the same procedure:
-5 == 1011 => 0100 + 1 == 0101 == 5
Does it really matter if I declare the value as signed or unsigned int?
Yes, for the following reasons:
It affects the values you can represent: unsigned integers can represent values from 0 to 2N-1, whereas signed integers can represent values between -2N-1 and 2N-1-1 (two's complement).
Overflow is well-defined for unsigned integers; UINT_MAX + 1 will "wrap" back to 0. Overflow is not well-defined for signed integers, and INT_MAX + 1 may "wrap" to INT_MIN, or it may not.
Because of 1 and 2, it affects arithmetic results, especially if you mix signed and unsigned variables in the same expression (in which case the result may not be well defined if there's an overflow).
An unsigned int and a signed int take up the same number of bytes in memory. They can store the same byte values. However the data will be treated differently depending on if it's signed or unsigned.
See http://en.wikipedia.org/wiki/Two%27s_complement for an explanation of the most common way to represent integer values.
Since you can typecast in C you can effectively force the compiler to treat an unsigned int as signed int and vice versa, but beware that it doesn't mean it will do what you think or that the representation will be correct. (Overflowing a signed integer invokes undefined behaviour in C).
(As pointed out in comments, there are other ways to represent integers than two's complement, however two's complement is the most common way on desktop machines.)
Does it really matter if I declare the value as signed or unsigned int?
Yes.
For example, have a look at
#include <stdio.h>
int main()
{
int a = -4;
int b = -3;
unsigned int c = -4;
unsigned int d = -3;
printf("%f\n%f\n%f\n%f\n", 1.0 * a/b, 1.0 * c/d, 1.0*a/d, 1.*c/b);
}
and its output
1.333333
1.000000
-0.000000
-1431655764.000000
which clearly shows that it makes a huge difference if I have the same byte representation interpreted as signed or unsigned.
#include <stdio.h>
int main(){
int x = 35, y = -35;
unsigned int z = 35, p = -35;
signed int q = -35;
printf("x=%d\tx=%u\ty=%d\ty=%u\tz=%d\tz=%u\tp=%d\tp=%u\tq=%d\tq=%u\t",x,x,y,y,z,z,p,p,q,q);
}
the result is:
x=35 x=35 y=-35 y=4294967261 z=35 z=35 p=-35 p=4294967261 q=-35 q=4294967261
the int number store is not different, it stored with Complement style in memory,
I can use 0X... the 35 in 0X00000023, and the -35 in 0Xffffffdd, it is not different you use sigend or unsigend. it only output with different sytle. The %d and %u is not different about positive, but the negative the first position is sign, if you output with %u is 0Xffffffdd equal 4294967261, but the %d the 0Xffffffdd can be - 0X00000023 equal -35.
The most fundamental thing that variable's type defines is the way it is stored (that is - read from and written to) in memory and how are the bits interpreted, so your statement can be considered "valid".
You can also look at the problem using conversions. When you store signed and negative value in unsigned variable it gets converted to unsigned. It so happens that this conversion is reversible, so signed -35 converts to unsigned 4294967261, which - when you request it - can be converted to signed -35. That's how 2's complement encoding (see link in other answer) works.

Concept of bit field

struct A
{
int a:2;
int b:3;
int c:3;
};
int main()
{
struct A p = {2,6,1};
printf("\n%d\n%d\n%d\n",p.a,p.b,p.c);
return 0;
}
Output is:
-2,-2,1
What would be output of above code in C complier and in C++ complier?
And Why?
Your system seems to using 2's complement. A 2-bit bit-field holding 2 would be 10 in binary which is -2 in 2's complement system. Likewise 110(6) is -2 for a 3-bit representation in 2's complement. And 1 is plain 1
Also read about signed bit-fields here
I get -2 -2 1 with my C compiler. The problem is that your bit fields are too small for the numbers you are trying to store. In the first two cases, the leftmost bits are 1's, so they are interpreted as negative numbers. To fix this, either:
Make your bit fields larger
Declare your bit fields as unsigned ints instead of ints
Cast to unsigned int before printing and use %u to print.
You get those answers for the same reason that this program:
#include <stdio.h>
#include <stdint.h>
int main(void)
{
int32_t a = 4294967294;
printf("%d\n", a);
return 0;
}
Has output -2. Initializing a signed variable with a number too large to fit causes it to be interpreted differently. From the spec:
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.
Now Lets see what exactly is happening. Lets start with the given code:
struct A
{
int a:3;
};
int main()
{
struct A p = {5};
printf("%d",p.a);
}
within 3 bits the values would be 101(5) since sign bit of this 3 bit set is 1 thus negative value. Thus we need to find 2's compliment of 101 which would be 011(3).
Thus by applying above logic we would output as -3. Similarly others could be proved.
e.g. for 1001(9) we shall take 3 bit values because of a:3. thus it would be 001(1). Since here sign bit is not set i.e. 1 so no need to use 2's complement. Straight forward answer would be 1.
Similarly others could be done.

why the result is "2" of unsigned int (1) - unsigned int (0xFFFFFFFF)

Please look at the following codes:
#include <stdlib.h>
#include <stdio.h>
int main()
{
unsigned int a = 1;
unsigned int b = -1;
printf("0x%X\n", (a-b));
return 0;
}
The result is 0x2.
I think the integer promotion should not happen because the type of both of "a" and "b" are unsigned int. But the result beats me.... I don't know the reason.
By the way, I know the arithmetic result should be 2 because 1-(-1)=2. But the type of b is unsigned int. When assign the (-1) to b, the value of b is 0xFFFFFFFF actually. It is the maximum value of unsigned int. When one small unsigned value subtract one big value, the result is not that I expect.
From the answer below, I think maybe the overflow is a good explanation。
Now I writes other test codes. It proves the overflow answer is right.
#include <stdlib.h>
#include <stdio.h>
int main()
{
unsigned int c = 1;
unsigned int d = -1;
printf("0x%llx\n", (unsigned long long)c-(unsigned long long)d);
return 0;
}
The result is "0xffffffff00000002". It is I expect.
unsigned int a = 1;
This initializes a to 1. Actually, since 1 is of type int, there's an implicit int-to-unsigned conversion, but it's a trivial conversion that doesn't change the value or representation).
unsigned int b = -1;
This is more interesting. -1 is of type int, and the initialization implicitly converts it from int to unsigned int. Since the mathematical value -1 cannot be represented as an unsigned int, the conversion is non-trivial. The rule in this case is (quoting section 6.3.1.3 of the C standard):
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.
Of course it doesn't actually have to do it that way, as long as the result is the same. Adding UINT_MAX+1 ("one more than the maximum value that can be represented in the new type") to -1 yields UINT_MAX. (That addition is defined mathematically; it's not itself subject to any type conversions.)
In fact, assigning -1 to an object of any unsigned type is a good way to get the maximum value of that type without having to refer to the *_MAX macros defined in <limits.h>.
So, assuming a typical 32-bit system, we have a == 1 and b == 0xFFFFFFFF.
printf("0x%X\n", (a-b));
The mathematical result of the subtraction is -0xFFFFFFFE, but that's obviously outside the range of unsigned int. The rules for unsigned arithmetic are similar to the rules for unsigned conversion; the result is 2.
Who says you're suffering integer promotion? Let's pretend that your integers are two's complement (likely, though not mandated by the standard) and they're only four bits wide (not possible according to the standard, I'm just using this to simplify things).
int unsigned-int bit-pattern
--- ------------ -----------
1 1 0001
-1 15 1111
------
(subtract with borrow) 1 0010
(only have four bits) 0010 -> 2
You can see here that you can get the result you see without any promotion to signed or wider types.
There should be a compiler warning that you probably ignored or turned off, but it's still possible to store -1 in an unsigned integer. Internally, -1 is stored on a 32-bit machine as 0xffffffff. So if you subtract 0xffffffff from 1, you end up with -0xfffffffe, which is 2. (There are no negative numbers, a negative number is the maximum integer value plus one minus the number).
Bottom line - signed or unsigned doesn't matter at all, it only comes to play when you compare values.
And mathematically speaking, 1 - (-1) = 1+1.
If you subtract a negative number, it is the equivalent of adding a positive number.
a = 1
b = -1
(a-b) = ?
((1)-(-1)) = ?
(1-(-1)) = ?
(1+1) = ?
2 = ?
At first you might think that this isn't allowed, since you specified an unsigned int; however, you are also converting signed int (the -1 constant) to an unsigned int. So, you are effectively storing the exact same bits into the unsigned int (0xFFFF).
Then, in the expression, you take the negative of the 0xFFFF value, which of course forces the number to be signed. In effect, you are circumventing the unsigned directive at ever step.

Resources