strange behaviour of char - c

If char a = -128; it is represented in binary as 10000000.
but when I shift this binary equivalent to the left side by by one bit it gives me -256 for which my brain doesn't make any sense.
Can anyone explain it to me how this strange behaviour comes?
int main(){
char a=-128;
printf("%d",a<<1);
return 0;
}

-128 on an int variable is 0xffffff80.
The shifting left result is 0xffffff00 that is -256.
You can test it with this code:
int main(void)
{
int n = -128;
printf("Decimal value = %d\n", n);
printf("Hex value = %x\n", n);
n<<=1;
printf("Decimal value = %d\n", n);
printf("Hex Value = %x\n", n);
return 0;
}
EDIT
In your code printf is promoting your char variable to int before shifting it.

As per the rule# of shifting operator,
The integer promotions are performed on each of the operands. [...]
So, while using a<<1 as the argument for printf(), a being of type char and 1 being the type of int (literal), a value is promoted to type int and then, the shifting will be performed, then the result will be printed out as an int value.
[#] - C11, chapter ยง6.5.7, Bitwise shift operators

Related

%d for unsigned integer

I accidentally used "%d" to print an unsigned integer using an online compiler. I thought errors would pop out, but my program can run successfully. It's good that my codes are working, but I just don't understand why.
#include <stdio.h>
int main() {
unsigned int x = 1
printf( "%d", x);
return 0;
}
The value of the "unsigned integer" was small enough that the MSB (most significant bit) was not set. If it were, printf() would have treated the value as a "negative signed integer" value.
int main() {
uint32_t x = 0x5;
uint32_t y = 0xC0000000;
printf( "%d %u %d\n", x, y, y );
return 0;
}
5 3221225472 -1073741824
You can see the difference.
With new-fangled compilers that "read into" printf format specifiers and match those with the datatypes of following parameters, it may be that the online compiler may-or-may-not have been able to report this type mismatch with a warning. This may be something you will want to look into.
refer to printf() manual, they said:
A character that specifies the type of conversion to be applied. The
conversion specifiers and their meanings are:
d, i
The int argument is
converted to signed decimal notation. The precision, if any, gives the
minimum number of digits that must appear; if the converted value
requires fewer digits, it is padded on the left with zeros. The
default precision is 1. When 0 is printed with an explicit precision
0, the output is empty.
so it means that the parameter even if it's in unsigned representation, it will be converted into its signed int representation and printed, see the following code example:
#include <stdio.h>
int main(){
signed int x1 = -2147483648;
unsigned int x2 = -2147483648;
unsigned long long x3 = -2147483648;
printf("signed int x1 = %d\n", x1);
printf("unsigned int x2 = %d\n", x2);
printf("signed long long x3 = %d\n", x3);
}
and this is the output:
signed int x1 = -2147483648
unsigned int x2 = -2147483648
signed long long x3 = -2147483648
so it means no matter what is the type of the variable printed, as long as you specified %d as format specifier, the variable will be converted into its representation in signed int and be printed
in case of unsigned char like for example:
#include <stdio.h>
int main(){
unsigned char s = -10;
printf("s = %d",s);
}
the output is :
s = 246
as the binary representation of unsigned char s = -10 is :
1111 0110
where the MSB bit is 1, but when it's converted into signed int, the new representation is :
0000 0000 0000 0000 0000 0000 1111 0110
so the MSB is no longer have that 1 bit in its MSB which represents whether the number is positive or negative.

Trouble understanding bit shifting as follows

So I have written the code below which takes an unsigned int , shifts its bits 6 positions to the left then replaces the empty final 6 bits with another int value. However, when I run the code say with value 15, the first step works and I get a value of 960 (so shifting left by 6 works). But the or step does not seem to work and I get -1 when I actually need to get 1111111111111111 or i.e. 65535 (note the operand value in this case is -1)? Any help would be greatly appreciated. I understand it is something to maybe do with my types but s->data was defined as an unsigned int whilst operand is defined as an int so I do not know why the output of s->data gives a negative value.
typedef struct state { int x, y, tx, ty; unsigned char tool; unsigned int start, data; bool end;} state;
void dataCommand(int operand, state *s) {
// shifts bits of current data fields six positions to left
printf("BEFORE SHIFTING %d\n", s->data);
s->data = s->data << 6;
printf("AFTER SHIFTING %d\n", s->data);
printf("OPERAND IS %d\n", operand);
// last 6 bits replaced with operand bits of the command
s->data = (s->data | operand);
printf("AFTER OR %d\n", s->data);
}
When operand is -1 it is actually 0xffffffff (32 ones in binary).
So when you are ORing you get back 32 ones which is still -1.
Maybe what you wanted to do was masking 6 bits off the operand :
s->data = (s->data << 6) | (operand & 0b111111);
You must mask the operand to select which bits are combined into the result.
-1 is converted to unsigned int in the s->data | operand expression, to the value UINT_MAX that has all bits set, hence oring operand sets all bits in the result, giving it a value of UINT_MAX, but since you use %d to output the value, you get -1.
Modify the code this way:
typedef struct state {
int x, y, tx, ty;
unsigned char tool;
unsigned int start, data;
bool end;
} state;
void dataCommand(int operand, state *s) {
// shifts bits of current data fields six positions to left
printf("BEFORE SHIFTING %u\n", s->data);
s->data = s->data << 6;
printf("AFTER SHIFTING %u\n", s->data);
printf("OPERAND IS %d (%#x)\n", operand, operand);
// last 6 bits replaced with operand bits of the command
s->data = s->data | (operand & 0x3F);
printf("AFTER OR %u\n", s->data);
}

Bitwise operation in character

I am curious about a behavior of bit-wise operator of C on Character.
#include <stdio.h>
int main()
{
int x = 108;
x = x<<1;
printf("%d\n", x);
char y = 108;
y = y<<1;
printf("%d", y);
//printf("%d", y<<1);
return 0;
}
Here, if I pass like this, y = y<<1, it's output was -40 and when I print it directly like,
printf("%d", y<<1);
it's output was 216.
How I can simulate it?
Note that there is really no << operation on char types - the operands of << are promoted to (at least) int types, and the result is, similarly, an int.
So, when you do y = y << 1, you are truncating the int result of the operation to a (signed) char, which leaves the most significant bit (the sign bit) set, so it is interpreted as a negative value.
However, when you pass y << 1 directly to printf, the resulting int is left unchanged.
y<<1 produces an int. To get -40, you were implicitly casting it to a char. In your printf case, you'll need to do the cast explicitly: (char)(y<<1)

Incorrect value printed by the 'pow' function in C

Why does the below code gives 127 as output, when it has to be 128. i have even tried to figure out, but I don't understand why 127?
#include<stdio.h>
#include<math.h>
int main()
{
signed char ch;
int size,bits;
size = sizeof(ch);
bits = size * 8;
printf("totals bits is : %d\n",bits);
printf("Range is : %u\n", (char)(pow((double)2, (double)(7))));
}
If you want 128 as result then typecast pow() result as int instead of char. for e.g
printf("Range is : %u\n", (int)(pow((double)2, (double)(7)))); /* this print 128 */
Why this
printf("Range is : %u\n", (char)(pow((double)2, (double)(7))));
prints 127 as pow((double)2,(double)7) is 128 but at same time that whole result vale explicitly type casted as char and default char is signed which ranges from -128 to +127 , hence it prints 127.
Side note, pow() is floating point function as #lundin suggested & same you can find here. you can use
unsigned char ch = 1 << 7;
to get the same in particular case.

Using unsigned data types in C

How to use unsigned int properly? My function unsigned int sub(int num1, int num2);doesn't work when user input a is less than b. If I simply use int, we can expect a negative answer and I need to determine which is larger before subtracting. I know that's easy but maybe there is a way to use unsigned int to avoid that?
For instance when a = 7 and b = 4, the answer is 3.000000. But when I flip them, the code gives me 4294967296.000000 which I think is a memory address.
#include <stdio.h>
unsigned int sub(int num1,int num2){
unsigned int diff = 0;
diff = num1 - num2;
return diff;
}
int main(){
printf("sub(7,4) = %u\n", sub(7,4));
printf("sub(4,7) = %u\n", sub(4,7));
}
output:
sub(7,4) = 3
sub(4,7) = 4294967293
Unsigned numbers are unsigned... This means that they cannot be negative.
Instead they wrap (underflow or overflow).
If you do an experiment with an 8-bit unsigned, then you can see the effect of subtracting 1 from 0:
#include <stdio.h>
#include <stdint.h>
int main(void) {
uint8_t i;
i = 1;
printf("i: %hhu\n", i);
i -= 1;
printf("i: %hhu\n", i);
i -= 1;
printf("i: %hhu\n", i);
return 0;
}
i: 1
i: 0
i: 255
255 is the largest value that an 8-bit unsigned can hold (2^8 - 1).
We can then do the same experiment with a 32-bit unsigned, using your 4 - 7:
#include <stdio.h>
#include <stdint.h>
int main(void) {
uint32_t i;
i = 4;
printf("i: %u\n", i);
i -= 7;
printf("i: %u\n", i);
return 0;
}
i: 4
i: 4294967293
4294967293 is effectively 0 - 3, which wraps to 2^32 - 3.
You also need to be careful of assigning an integer value (the return type of your sub() function) to a float... Generally this is something to avoid.
See below. x() returns 4294967293 as an unsigned int, but it is stored in a float... This float is then printed as 4294967296???
#include <stdio.h>
#include <stdint.h>
unsigned int x(void) {
return 4294967293U;
}
int main(void) {
float y;
y = x();
printf("y: %f\n", y);
return 0;
}
y: 4294967296.000000
This is actually to do with the precision of float... it is impossible to store the absolute value 4294967293 in a float.
What you see is called unsigned integer overflow. As you noted, unsigned integers can't hold negative numbers. So when you try to do something that would result in a negative number, seemingly weird things can occour.
If you work with 32-bit integers,
int (int32_t) can hold numbers between (-2^31) and (+2^31-1), INT_MIN and INT_MAX
unsigned int (uint32_t) can hold numbers between (0) and (2^32-1), UINT_MIN and UINT_MAX
When you try to add something to an int that would lead to a number greater than the type can hold, it will overflow.
unsigned int cannot be used to represent a negative variable. I believe what you wanted is to find the absolute value of the difference between a and b. If so, you can use the abs() function from stdlib.h. The abs() function takes in an int variable i and returns the absolute value of i.
The reason why unsigned int returns a huge number in your case is due to the way integers are represented in the system. You declared diff as an int type, which is capable of storing a negative value, but the same sequence of bits that represents -3 when interpreted as unsigned int represents 4294967296 instead.
It becomes a negative number, unsigned data types dont hold negative number, so instead it becomes a large number
"absolute value of the difference between a and b" does not work for many combinations of a,b. Any a-b that overflows is undefined behavior. Obviously abs(INT_MAX - INT_MIN) will not generate the correct answer.
Also, using abs() invokes undefined behavior with a select value of int. abs(INT_MIN) is undefined behavior when -INT_MIN is not representable as an int.
To calculate the absolute value difference of 2 int, subtract them as unsigned.
unsigned int abssub(int num1,int num2){
return (num1 > num2) ? (unsigned) num1 - num2 : (unsigned) num2 - num1;
}

Resources