What I know about unsigned numerics (unsigned short, int and longs), that It contains positive numbers only, but the following simple program successfully assigned a negative number to an unsigned int:
1 /*
2 * =====================================================================================
3 *
4 * Filename: prog4.c
5 *
6 * =====================================================================================
7 */
8
9 #include <stdio.h>
10
11 int main(void){
12
13 int v1 =0, v2=0;
14 unsigned int sum;
15
16 v1 = 10;
17 v2 = 20;
18
19 sum = v1 - v2;
20
21 printf("The subtraction of %i from %i is %i \n" , v1, v2, sum);
22
23 return 0;
24 }
The output is :
The subtraction of 10 from 20 is -10
%i is the format specifier for a signed integer; you need to use %u to print an unsigned integer.
With printf, the %i format outputs a signed int. Use %u to output an unsigned int. This is a common issue when beginning C programming. To address your question, the result of v1 - v2 is -10, but sum is an unsigned int, so the real answer is probably something like 4294967286 (232 - 10). See what you get when you use The subtraction of %i from %i is %u \n. :)
Signed int and unsigned int are the same size in memory, the only difference between them is how you intepret them. Signed values use a twos complement representation.
If you put 0xFFFFFFFF in a 4 byte memory location, and then ask what is the value in there? Well if we interpret it as a signed int, then it is -1, but if we interpret it as an unsigned int then the value is 4294967295. Either way it's the same bit pattern, the difference is what meaning you give it.
When you assigned 10 - 20 into an unsigned int, you calculated a value of -10 (C doesn't do overflow or underflow checking), that's a bit pattern of 0xFFFFFFF6, which means -10 in a signed int or 4294967286 in an unsigned int. If you then tell the compiler (by using %i) to print a signed int then it interprets that bit pattern as a signed int and prints -10, if you told the compiler (by using %u) to print an unsigned int then it interprets that bit pattern as unsigned and prints 4294967286.
Because unsigned int value that is stored in sum is treated like signed decimal integer in printf %i
Related
I know there was very similar question already answered but I believe it doesn't address my problem.
unsigned char aaa = -10;
unsigned int bbb = (unsigned int)-5;
unsigned int ccc = (unsigned int)20 + (unsigned int)bbb;
printf("%d\n", aaa);
printf("%d\n", ccc);
Above code prints aaa = 246 (which is what I would expect) but ccc = 15 which means unsigned int was treated all the way as signed. I can't find explanation for this even trying probably obsolete typecasting.
unsigned char aaa = -10;
The int value -10 will be converted to unsigned char by repeatedly adding UCHAR_MAX + 1 until it the result will in range of [0, UCHAR_MAX]. Most probablly the char has 8-bits on your system, that means UCHAR_MAX = 2**8 - 1 = 255. So -10 + UCHAR_MAX + 1 is 246, it's in range. So aaa = 246.
unsigned int bbb = (unsigned int)-5;
The -5 is added UINT_MAX + 1, assuming int has 32bits, it results in bbb = 4294967291.
unsigned int ccc = (unsigned int)20 + (unsigned int)bbb;
Unsigned integer overflow "wrap around". So 20 + 4294967291 = 4294967311 is greater then UINT_MAX = 2**32 - 1 = 4294967295. So we subtract UINT_MAX+1 until we will be in range [0, UINT_MAX]. So 4294967311 - (UINT_MAX+1) = 15.
printf("%d\n", aaa);
The code is most probably fine. Most probably on your platform unsigned char is promoted to int before passing into variadic function argument. For reference about promotions you could read cppreference implicit conversions. Because %d expects an int and unsigned char is promoted to int, the code is fine. [1]
printf("%d\n", ccc);
This line results in undefined behavior. ccc has the type unsigned int, while %d printf format specifier expects an signed int. Because your platform uses two-s complement to represent numbers, this just results in printf interpreting the bits as a signed value, which is 15 anyway.
[1]: There is a theoretical possibility of unsigned char having as many bits as int, so unsigned char will get promoted to unsigned int instead of int, which will result in undefined behavior there too.
C variable types
C is a quite low-level programming language, and it does not preserve variable types after compilation. For example, if one had both a unsigned and an unsigned variables of equal size (say uint64_t and int64_t), after the compilation ends, each of them will be represented as just an 8-byte piece of memory. All the addition/subtraction will be performed modulo 2 in the corresponding power (64 for 64-bit variables and 32 for 32-bit ones).
The only difference, which remains after compilation is in the comparison. For example, (unsigned) -5 > 1, but -5 < 1. I will explain why now
Your -5 will be stored modulo 2^32, just like every 32-bit value. -5 will be presented as 0xfffffffb in actual ram. The algorithm is simple: if a variable is signed, then it's first bit is called a sign bit and indicates, whether it's positive or negative. The first bit of 0xfffffffb is 1, so, when it comes to signed comparison, it is negative, and is less, than 1. But when compared as an unsigned integer, this value is actually a huge one, 2^32 - 5. So, in general, unsigned representation of a negative signed number is greater by 2^[num of bits in that number]. You can read more about this binary arithmetics here.
So, all, that happened, you got an unsigned number, equal to 0xfffffffb + 0x14 modulo 2^32, which is 0x10000000f (mod 2^32), and that is 0xf = 15.
In conclusion, "%d" assumes it's argument is signed. But that's not the main reason, why the answer happened. However, I advice using %u for unsigned numbers.
This question already has answers here:
Unsigned and Signed int and printf
(2 answers)
Closed 6 years ago.
I know that the range of unsigned int is 0<= I <= 2^32-1
However, when I type like this in C(visual 2015)
void main(){
unsigned int k = -10;
printf("%d",k);
}
then why computer print -10 on screen?? I think there should be error.
int stores signed numbers by default, which means they can go from -2,147,483,648 to 2,147,483,647 in range. An unsigned int means you won't be using negative numbers, so the range is much larger because you have freed up the left most bit in your number which is normally used to indicate that it is signed (negative) or not. So an unsigned int can go from 0 to 4,294,967,295. This applies to types like char as well, they normally go from -128 to 127, when unsigned, a char holds one byte exactly, or 0 to 255.
Visual Studio (and most compilers) should give you a warning for trying to store a signed value into an unsigned type.
When you used printf("%d",k) The %d is telling printf() to print out a signed int. So that is what it did. If you want printf() to print out an unsigned int than you needed to use printf("%u").
in hexadecimal form, -10 is 0xFFFFFFF6
unsigned int k = -10; means
unsigned int k = 0xFFFFFFF6;
and when printing this value if you say
printf("%d",k); the compiler will evaluate the value (0xFFFFFFF6) as integer because of the %d specifier. (check http://www.cplusplus.com/reference/cstdio/printf/ about the issue)
if you say printf("%u",k); the compiler will evaluate the value (0xFFFFFFF6) as unsigned integer and will print a value between 0-2^32-1
On IndiaBix.com I came across the following question.As per my experience level(beginner in C) the output of above should be 0 (10000000 << 1 is 00000000) but it came out to be 256,after going some deeper I found that we are printing using %d which supports 4 bytes so the output is 256 instead of 0.
#include<stdio.h>
int main()
{
unsigned char i = 128;
printf("%d \n", i << 1);
return 0;
}
Now Consider the following Example
#include<stdio.h>
int main()
{
unsigned int i = 2147483648;(bit 31 = 1 and b0 to b30 are 0)
printf("%d \n", i<<1);
return 0;
}
When I left shift the above I get 0 as the output, As %d supports value of int the output should be 0 but when I Changed %d to %ld the output is still 0. As %ld supports values upto long int the output should not be 0.Why i am getting 0 as the output.
In the first case, i is promoted to int, which can store at least 32767, then shift is calculated. As a result, the result became 256.
In the second case, if your unsigned int is 32-bit long, it is calculated in unsigned int and the result wraps. As a result, the result became 0.
You have to cast to larger type to get what you want.
#include<stdio.h>
#include<inttypes.h>
int main()
{
unsigned int i = 2147483648;//(bit 31 = 1 and b0 to b30 are 0)
printf("%"PRIu64" \n", (uint64_t)i<<1);
return 0;
}
Its not the %d or %ld that matters here.
Its probably because the size of unsigned int on your machine in 4 bytes.
Also you can't use %ld with unsigned int. It is undefined behavior.
The first problem is that 2147483648 (80000000h) will fit inside your 32 bit unsigned int, but it will not fit inside the signed int that printf expects when you use the %d specifier. Instead, use the %u specifier.
When that is fixed, note that 0x80000000 << 1 is supposed to be 0 if unsigned int is 32 bits.
Changing the format specifier of printf to %ld does not change the type of the expression! You need to change both the format specifier and the expression, if you want a larger type.
You are getting tricked by the behavior of the first char print. The reason why %d works there is because printf (like any variadic function) internally promotes all arguments to be at least the size of int. So the expression got implicitly promoted to int and as it happens, that matches with %d.
Though in the case of my_char << n, the << operator already integer promote both operands to int and the result of a shift always has the type of the possibly promoted left operand.
As you can tell, the various implicit type promotion rules in C aren't trivial and can therefore easily create bugs. It is one of many well-known flaws of the language.
According to the C Standard (6.5.7 Bitwise shift operators)
3 The integer promotions are performed on each of the operands.
The type of the result is that of the promoted left operand....
and (6.3.1.1 Boolean, characters, and integers)
...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.58) All other types are unchanged by
the integer promotions.
This means that an operand of type unsigned char is promoted to type int because type int can represent all values of type unsigned char.
So in expression
i << 1
operand i is promoted to type int and you will get (let's assume that type int has 32 bits)
0x00000080 << 1
After the operation you will get result
0x00000100
that corresponds to decimal
256
and this statement
printf("%d \n", i << 1);
outputs this result.
Now consider this code snippet
unsigned int i = 2147483648;(bit 31 = 1 and b0 to b30 are 0)
printf("%d \n", i<<1);
Here i can be represented like
0x80000000
The integer promotions are applied to types that have the conversion rank less than the rank of type int.
So the integer promotions will not be applied to variable i because it does not has a rank less than the rank of int.
After the operations you will get
0x00000000
that is you will get decimal
0
and this statement
printf("%d \n", i<<1);
will correctly output this zero because its representation is the same for unsigned and signed integer objects.
Even if you write for example
printf( "%lld \n", ( long long int )( i<<1 ));
you will get the same result because the type of expression i << 1 in any case is unsigned int
However if you will write
printf( "%lld \n", ( long long int )i << 1 );
then operand i will be converted to type long long int and you will get
0x0100000000
Changing %d to %id will not be effective
Change datatype to unsigned it to that will help you to increase your integer limit
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
Why the result of ~10 is -11? Shouldn't it be 5 as the ~ operations flips every bit.
10 = 1010
~10= 0101 //5 in decimal
#include<stdio.h>
int main()
{
unsigned int b =10;
b= ~b;
printf("bitwise %d\n ",b);
return 0;
}
Many things wrong with this.
You're bit-negating an unsigned int and then printing it as a signed int (%d is for signed integers). Print the result as an unsigned int and you will realize...
on a 32bit-int machine, 10(decimal) is not 1010(binary) but 000000000000000000000000000001010.
Finally, convert everything back to signed integers and learn about two's complement notation to find out how negative numbers are stored in your computer.
Don't forget that you are flipping every bit, including the most significant bit (sign bit for signed variables). Defining a variable as unsigned doesn't change the binary representation, only how the program uses it.
So when you print the number out as signed (%d) you will get -11.
10 = 0x0000000A (10)
~10 = 0xFFFFFFF5 (-11 signed / 4294967285 unsigned)
To print out as unsigned use:
printf("bitwise %u\n ",b);