Bit field manipulation-setting a bit - c

#include<stdio.h>
int main()
{
struct s{
int bit_fld:3;
};
s a;
a.bit_fld=0x10;
a.bit_fld =( a.bit_fld | (1<<2));
printf("%x\n",a.bit_fld);
return 0;
}
This program outputs fffffffc.
I tried to do manual calculation of the output and I could not get the output that the compiler produced.
bit_fld = 00010000 and (1<<2) = 0100 oring both wil result in 00010100 which is 0x14 in hexadecimal.
Why my perception of the output is wrong ? Help me to understand where I'm mistaken.

a.bit_fld is only 3 bits big, it can't store the value 0x10. Behavior is implementation-defined, but in this case it has probably stored 0.
Then 1 << 2 is binary 100 as you say. Assuming we did store 0 at the first step, the result of ( a.bit_fld | (1<<2)) is an int with value 4 (binary 100).
In a signed 2's complement 3-bit representation, this bit pattern represents the value -4, so it's not at all surprising if -4 is what you get when you store the value 4 to a.bit_fld, although again this is implementation-defined.
In the printf, a.bit_fld is promoted to int before passing it as a vararg. The 2's complement 32 bit representation of -4 is 0xfffffffc, which is what you see.
It's also undefined behavior to pass an int instead of an unsigned int to printf for the %x format. It's not surprising that it appears to work, though: for varargs in general there are certain circumstances where it's valid to pass an int and read it as an unsigned int. printf isn't one of them, but an implementation isn't going to go out of its way to stop it appearing to work.

Related

I dont understand the behaviour of bitshifting in this example

I understand that shifting means moving each bit to the left or right respectively,but when I try to shift 0x30 by 4 positions to the left I get 0x300 or 00110000000 in binary.(my desired output would be 0000 0000 ).Why does it behave this way?
My code in C:
int main(void){
unsigned int a;
scanf("%x",&a);
printf("%b",a<<4);
}
Input:30
Output:300
Expected output:0
Edit:I would expect this output if I use more than 1 byte for my assigned variable ,but unsigned int is exactly 1 byte and 0x300 is 12 bits.
a is an int which is (usually) 32 bits long.
The value of 0x300 is expected for an int.
Even if you use a uint8_t for a you need to typecast the result back to uint8_t to see the expected result.
int main(void){
uint8_t a;
scanf("%hhx",&a); // you need hhx to read unsigned char (C99 only)
printf("%hhx",(uint8_t) (a<<4));
}
For your information, if you do not typecast, the value a<<4 will be promoted to int and 0x300 will be displayed
0x30 is hex and 0000000000110000 in binary. If you shift 4 bits, you get your result 0x300 or 0000001100000000.
To respond to your edit, unsigned int does not take 1 byte. It takes the same number of bytes as an int does. Which in your case it is probably 4 bytes or 32 bits.
The reason the number is shown with 2 or 3 hex digits, its because the 0-s in the beginning are not printed. But the number is in fact 0030(hex) .
Anyway, you can check the size using sizeof.
EDIT: If you want to take 1 byte, see Rishikesh answer.

why is it printing 255

int main()
{
unsigned char a = -1;
printf("%d",a);
printf("%u",a);
}
when i have executed the above program i got 255 255 as the answer.
we know negative numbers will be stored in 2's complement.
since it is 2's complement the representation would be
1111 1111 -->2's complement.
but in the above we are printing %d(int) but integer is four bytes.
my assumption is even though it is character we are forcing compiler to treat it as integer.
so it internally uses sign extension concept.
1111 1111 1111 1111 1111 1111 1111 1111.
according to the above representation it has to be -1 in the first case since it is %d(signed).
in the second case it has to print (2^31- 1) but it is printing 255 and 255.
why it is printing 255 in both cases.
tell me if my assumption is wrong and give me the real interpretation.
Your assumption is wrong; the character will "roll over" to 255, then be padded to the size of an integer. Assuming a 32-bit integer:
11111111
would be padded to:
00000000 00000000 00000000 11111111
Up to the representation of a, you are correct. However, the %d and %u conversions of the printf() function both take an int as an argument. That is, your code is the same as if you had written
int main() {
unsigned char a = -1;
printf("%d", (int)a);
printf("%u", (int)a);
}
In the moment you have assigned -1 to a you have lost the information that it once was a signed value, the logical value of a is 255. Now, when you convert an unsigned char to an int, the compiler preserves the logical value of a and the code prints 255.
The compiler doesn't know what type the extra parameters in printf should be, since the only thing that specifies it should be treated as a 4-byte int is the format string, which is irrelevant at compile time.
What actually happens behind the scenes is the callee (printf) receives a pointer to each parameter, then casts to the appropriate type.
Roughly the same result as this:
char a = -1;
int * p = (int*)&a; // BAD CAST
int numberToPrint = *p; // Accesses 3 extra bytes from somewhere on the stack
Since you're likely running on a little endian CPU, the 4-byte int 0x12345678 is arranged in memory as | 0x78 | 0x56 | 0x34 | 0x12 |
If the 3 bytes on the stack following a are all 0x00 (they probably are due to stack alignment, but it's NOT GUARANTEED), the memory looks like this:
&a: | 0xFF |
(int*)&a: | 0xFF | 0x00 | 0x00 | 0x00 |
which evaluates to *(int*)&a == 0x000000FF.
unsigned char runs from 0-255 So the negative number -1 will print 255 -2 will print 254 and so on...
signed char runs from -128 to +127 so you get -1 for the same printf() which is not the case with unsigned char
Once you make a assignment to a char then the rest of the integer values will be padded so your assumption of 2^31 is wrong.
The negative number is represented using 2's complement(Implementation dependent)
So
1 = 0000 0001
So in order to get -1 we do
----------------------------------------
2's complement = 1111 1111 = (255) |
-----------------------------------------
It is printing 255, simply because this is the purpose from ISO/IEC9899
H.2.2 Integer types
1 The signed C integer types int, long int, long long int, and the corresponding
unsigned types are compatible with LIA−1. If an implementation adds support for the
LIA−1 exceptional values ‘‘integer_overflow’’ and ‘‘undefined’’, then those types are
LIA−1 conformant types. C’s unsigned integer types are ‘‘modulo’’ in the LIA−1 sense
in that overflows or out-of-bounds results silently wrap. An implementation that defines
signed integer types as also being modulo need not detect integer overflow, in which case,
only integer divide-by-zero need be detected.
If this is given, printing 255 is absolutly that, what the LIA-1 would expect.
Otherwise, if your implementation doesn't support C99's LIA-1 Annex part, then its simply undefined behaving.

Structure with signed integer bit-fields resulting minus outputs

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

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.

Assigning negative numbers to an unsigned int?

In the C programming language, unsigned int is used to store positive values only. However, when I run the following code:
unsigned int x = -12;
printf("%d", x);
The output is still -12. I thought it should have printed out: 12, or am I misunderstanding something?
The -12 to the right of your equals sign is set up as a signed integer (probably 32 bits in size) and will have the hexadecimal value 0xFFFFFFF4. The compiler generates code to move this signed integer into your unsigned integer x which is also a 32 bit entity. The compiler assumes you only have a positive value to the right of the equals sign so it simply moves all 32 bits into x. x now has the value 0xFFFFFFF4 which is 4294967284 if interpreted as a positive number. But the printf format of %d says the 32 bits are to be interpreted as a signed integer so you get -12. If you had used %u it would have printed as 4294967284.
In either case you don't get what you expected since C language "trusts" the writer of code to only ask for "sensible" things. This is common in C. If you wanted to assign a value to x and were not sure whether the value on the right side of the equals was positive you could have written unsigned int x = abs(-12); and forced the compiler to generate code to take the absolute value of a signed integer before moving it to the unsigned integer.
The int is unsinged, but you've told printf to look at it as a signed int.
Try
unsigned int x = -12; printf("%u", x);
It won't print "12", but will print the max value of an unsigned int minus 11.
Exercise to the reader is to find out why :)
Passing %d to printf tells printf to treat the argument as a signed integer, regardless of what you actually pass. Use %u to print as unsigned.
It all has to do with interpretation of the value.
If you assume 16 bit signed and unsigned integers, then here some examples that aren't exactly correct, but demonstrate the concept.
0000 0000 0000 1100 unsigned int, and signed int value 12
1000 0000 0000 1100 signed int value -12, and a large unsigned integer.
For signed integers, the bit on the left is the sign bit.
0 = positive
1 = negative
For unsigned integers, there is no sign bit.
the left hand bit, lets you store a larger number instead.
So the reason you are not seeing what you are expecting is that.
unsigned int x = -12, takes -12 as an integer, and stores it into x. x is unsigned, so
what was a sign bit, is now a piece of the value.
printf lets you tell the compiler how you want a value to be displayed.
%d means display it as if it were a signed int.
%u means display it as if it were an unsigned int.
c lets you do this kind of stuff. You the programmer are in control.
Kind of like a firearm.
It's a tool.
You can use it correctly to deal with certain situations,
or incorrectly to remove one of your toes.
one possibly useful case is the following
unsigned int allBitsOn = -1;
That particular value sets all of the bits to 1
1111 1111 1111 1111
that can be useful sometimes.
printf('%d', x);
Means print a signed integer. You'll have to write this instead:
printf('%u', x);
Also, it'll still not print "12", it's going to be "4294967284".
They do store positive values. But you're outputting the (very high) positive value as a signed integer, so it gets re-interpreted again (in an implementation-defined fashion, I might add).
Use the format flag "%u instead.
Your program has undefined behavior because you passed the wrong type to printf (you told it you were going to pass an int but you passed an unsigned int). Consider yourself lucky that the "easiest" thing for the implementation to do was just silently print the wrong value and not jump to some code that does something harmful...
What you are missing is that the printf("%d",x) expects x to be signed, so although you assign -12 to x it is interpreted as 2's complement which would be a very large number.
However when you pass this really large number to printf it interprets it as signed thus correctly translating it back to -12.
The correct syntax to print a unsigned in print f is "%u" - try this and see what it does!
The assignment of a negative value to an unsigned int does not compute the absolute value of the negative: it interprets as an unsigned int the binary representation of the negative value, i.e., 4294967284 (2^32 - 12).
printf("%d") performs the opposite interpretation. This is why your program displays -12.
int and unsigned int are used to allocate a number of bytes to store a value nothing more.
The compiler should give warnings about signed mismatching but it really does not affect the bits in the memory that represent the value -12.
%x, %d, %u etc tells the compiler how to interrupt a number of bits when you print them.
When you are trying to display the int value you are passing it to a (int) argument and not a (unsigned int) argument and that causes it to print -12 and not 4294967284. Integers are stored in hexadecimal format and -12 for int is the same as 4294967284 for unsigned int in hexadecimal format..
That is why "%u" prints the right value you want and not "%d".. It depends on your argument type..GOOD LUCK!
The -12 is in 16-bit 2's compliment format. So do this:
if (x & 0x8000) { x = ~x+1; }
This will convert the 2's compliment -ve number to the equivalent +ve number. Good luck.
When the compiler implicitly converts -12 to an unsigned integer, the underlying binary representation remains unaltered. This conversion is purely semantic. The sign bit of the two's complement integer becomes the most significant bit of the unsigned integer. Thus when printf treats the unsigned integer as a signed integer with %d, it will see -12.
In general context when only positive numbers can be stored, negative numbers are not stored explicitly but their 2's complement is stored. In the same way here, the 2's complement of -12 will be stored in 'x' and you use %u to get it.

Resources