I dont understand the behaviour of bitshifting in this example - c

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.

Related

Type casting a 16 bit unsigned integer to an 8 bit unsigned integer pointer in C

While playing around with pointers I came around something interesting.
I initialized a 16 bit unsigned int variable to the number 32771 and then assigned the address of that variable to an 8 bit unsigned int pointer.
Now 32771, in unsigned 16 bit form, has binary representation of 110000000000001. So when dereferencing the 8 bit pointer the first time, I expected it to print the value of 11000000, which is = 192 and after incrementing the pointer and then dereferencing the pointer again, is expected it to print the value 00000001, which is 128.
In actuality, for the first dereference, 3 was printed, which is what I would get if I read 11000000 from left to right and the second dereference printed 128.
int main(){
__uint16_t a = 32771;
__uint8_t *p = (__uint8_t *)&a;
printf("%d", *p); //Expected 192 but actual output 3.
++p;
printf("%d", *p); //Expected 1, but actual output 128
}
I know that bits are read from right to left, however in this case the bits are being read from left to right. Why?
32771 is 32768 plus 3. In binary, it's 1000000000000011.
If you split it into the most significant byte and the last significant byte, you get 128 and 3 because 128 * 256 + 3 = 32771.
So the bytes will be 3 and 128. There's no particular reason one should occur before the other. Your CPU can store the bytes that compose a multi-byte number in whatever order it wants to. Apparently, yours stores the least significant byte at a lower address than the most significant byte.

Why this program output 64?

I found this program during an online test on c programming I tried it on my level but I cannot figure it out that why the output of this program comes out to be 64.
Can anyone explain the concept behind this?
#include <iostream>
#include <stdio.h>
using namespace std;
int main()
{
int a = 320;
char *ptr;
ptr = (char *)&a;
printf("%d",*ptr);
return 0;
}
output:
64
Thankyou.
A char * points to one byte only. Assuming a byte on your system is 8 bits, the number 320 occupies 2 bytes. The lower byte of those is 64, the upper byte is 1, because 320 = 256 * 1 + 64. That is why you get 64 on your computer (a little-endian computer).
But note that on other platforms, so called big-endian platforms, the result could just as well be 1 (the most significant byte of a 16 bit/2 byte value) or 0 (the most significant byte of a value larger than 16 bit/2 bytes).
Note that all this assumes that the platform has 8-bit bytes. If it had, say 10-bit bytes, you would get a different result again. Fortunately, most computers have 8-bit bytes nowadays.
You won't be able to understand this unless you know about:
hex/binary represenation, and
CPU endianess.
Type out the decimal number 320 in hex. Split it up in bytes. Assuming int is 4 bytes, you should be able to tell which parts of the number that goes in which bytes.
After that, consider the endianess of the given CPU and sort the bytes in that order. (MS byte first or LS byte first.)
The code accesses the byte allocated at the lowest address of the integer. What it contains depends on the CPU endianess. You'll either get hex 0x40 or hex 0x00.
Note: You shouldn't use char for these kind of things, because it has implementation-defined signedness. In case the data bytes contains values larger than 0x7F, you might get some very weird bugs, that inconsistently appear/disappear across multiple compilers. Always use uint8_t* when doing any form of bit/byte manipulation.
You can expose this bug by replacing 320 with 384. Your little endian system may then either print -128 or 128, you'll get different results on different compilers.
What #Lundin said is enough.
BTW, maybe some basic knowledge is helpful. 320 = 0x0140. a int = 4 char. So when print the first byte, it output 0x40 = 64 because of cpu endianess.
ptr is char pointer of a. Thus *ptr will give char value of a. char occupies only 1 byte thus it repeats its values after 255. That is 256 becomes 0, 257 becomes 1 and so on. Thus 320 becomes 64.
Int is four byte data byte while char is one byte data byte, char pointer can keep the address one byte at time. Binary value of 320 is 00000000 00000000 00000001 01000000. So, char pointer ptr is pointing to only first byte.
*ptr i.e. content of first byte is 01000000 and its decimal value is 64.

how do we get the following output?

#include <stdio.h>
int main(void)
{
int i = 258;
char ch = i;
printf("%d", ch)
}
the output is 2!
How the range of variable works? what is the range of different data types in c langauge?
When assigning to a smaller type the value is
truncated, i.e. 258 % 256 if the new type is unsigned
modified in an implementation-defined fashion if the new type is signed
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.
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.
So all that fancy "adding or subtracting" means it is assigned as if you said:
ch = i % 256;
char is 8-bit long, while 258 requires nine bits to represent. Converting to char chops off the most significant bit of 258 which is 100000010 in binary, resulting in 10, which is 2 in binary.
When you pass char to printf, it gets promoted to int, which is then picked up by the %d format specifier, and printed as 2.
#include <stdio.h>
int main(void)
{
int i = 258;
char ch = i;
printf("%d", ch)
}
Here i is 0000000100000010 on the machine level. ch takes 1 byte, so it takes last 8 bit, it is 00000010, it is 2.
In order to find out how long various types are in C language you should refer to limits.h (or climits in C++). char is not guaranteed to be 8 bits long . It is just:
smallest addressable unit of the machine that can contain basic character set. It is an integer type. Actual type can be either signed or unsigned depending on implementation
Same sort of vague definitions are put for other types.
Alternatively, you can use operator sizeof to dynamically find out size of the type in bytes.
You may not assume exact ranges of native C data types. Standard places only minimal restrictions, so you can say unsigned short can hold at least 65536 different values. Upper limit can differ
Refer to Wikipedia for more reading
char is on 8 bits so, when you cast (you assign an integer to a char), in 32 bits machine, the i (int is on 32 bits) var is:
00000000 00000000 00000001 00000010 = 258 (in binary)
When you want a char from this int, you truncate the last 8 bits (char is on 8 bits), so you get:
00000010 which mean 2 in decimal, this is why you see this output.
Regards.
This is an overflow ; the result is undefined because char may be signed (undefined behavior) or unsigned (well-defined "wrap-around" behavior).
You are using little-endian machine.
Binary representation of 258 is
00000000 00000000 00000001 00000010
while assigning integer to char, only 8 byte of data is copied to char. i.e LSB.
Here only 00000010 i.e 0x02 will be copied to char.
The same code will gives zero, in case of big-endian machine.

Bit field manipulation-setting a bit

#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.

bit shift different result in similar programs

Here is one program
#include<stdio.h>
#include<stdlib.h>
int main()
{
unsigned char a=0x80;
printf("%d\n",a<<1);
}
The output of above is 256
Now here is one more version of above program
#include<stdio.h>
#include<stdlib.h>
int main()
{
unsigned char a=0x80;
a=a<<1;
printf("%d\n",a);
}
The output of above is
0
As far as my understanding is I am not able to see any difference between the two?
i.e. why is output coming 256 in first one and 0 in second program what is the difference in statements in both?
On your platform, unsigned char is only 8 bits wide, so a << 1 shifts the 1 out the left end when you assign it back to the narrow a. In the printf call, on the other hand, a is first promoted to an integer (which is wider than 8 bits on your platform) and thus the bit survives.
The expression a << 1 is of type int according to the C language's type-promotion rules. In the first program, you are taking this int, which now has the value 0x100, and passing it directly to printf(), which works as expected.
In the second program, your int is assigned to an unsigned char, which results in truncation of 0x100 to 0x00.
<< promotes the result to an (unsigned) int, but in the second example, you force it back into an (unsigned) char where it overflows back to 0.
In the second case, a is only 8 bit long, 0x80 << 1 is 0x100 then cast to a char clips the top bit so becomes 0x00
When directly in the printf statement, it is looking for an int so it won't clip it...

Resources