%d for unsigned integer - c

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.

Related

Error on casting unsigned int to float

For the following program.
#include <stdio.h>
int main()
{
unsigned int a = 10;
unsigned int b = 20;
unsigned int c = 30;
float d = -((a*b)*(c/3));
printf("d = %f\n", d);
return 0;
}
It is very strange that output is
d = 4294965248.000000
When I change the magic number 3 in the expression to calculate d to 3.0, I got correct result:
d = 2000.000000
If I change the type of a, b, c to int, I also got correct result.
I guess this error occurred by the conversion from unsigned int to float, but I do not know details about how the strange result was created.
I think you realize that you casting minus to unsigned int before assignment to float. If you run the below code, you will get highly likely 4294965296
#include <stdio.h>
int main()
{
unsigned int a = 10;
unsigned int b = 20;
unsigned int c = 30;
printf("%u", -((a*b)*(c/3)));
return 0;
}
The -2000 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
0xFFFFF830. 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 0xFFFFF830 which is 4294965296 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 -2000. If you had used
%u it would have printed as 4294965296.
#include <stdio.h>
#include <limits.h>
int main()
{
float d = 4294965296;
printf("d = %f\n\n", d);
return 0;
}
When you convert 4294965296 to float, the number you are using is long to fit into the fraction part. Now that some precision was lost. Because of the loss, you got 4294965248.000000 as I got.
The IEEE-754 floating-point standard is a standard for representing
and manipulating floating-point quantities that is followed by all
modern computer systems.
bit 31 30 23 22 0
S EEEEEEEE MMMMMMMMMMMMMMMMMMMMMMM
The bit numbers are counting from the least-significant bit. The first
bit is the sign (0 for positive, 1 for negative). The following
8 bits are the exponent in excess-127 binary notation; this
means that the binary pattern 01111111 = 127 represents an exponent
of 0, 1000000 = 128, represents 1, 01111110 = 126 represents
-1, and so forth. The mantissa fits in the remaining 24 bits, with
its leading 1 stripped off as described above. Source
As you can see, when doing conversion 4294965296 to float, precision which is 00011000 loss occurs.
11111111111111111111100 00011000 0 <-- 4294965296
11111111111111111111100 00000000 0 <-- 4294965248
This is because you use - on an unsigned int. The - inverts the bits of the number. Lets print some unsigned integers:
printf("Positive: %u\n", 2000);
printf("Negative: %u\n", -2000);
// Output:
// Positive: 2000
// Negative: 4294965296
Lets print the hex values:
printf("Positive: %x\n", 2000);
printf("Negative: %x\n", -2000);
// Output
// Positive: 7d0
// Negative: fffff830
As you can see, the bits are inverted. So the problem comes from using - on unsigned int, not from casting unsigned intto float.
As others have said, the issue is that you are trying to negate an unsigned number. Most of the solutions already given have you do some form of casting to float such that the arithmetic is done on floating point types. An alternate solution would be to cast the results of your arithmetic to int and then negate, that way the arithmetic operations will be done on integral types, which may or may not be preferable, depending on your actual use-case:
#include <stdio.h>
int main(void)
{
unsigned int a = 10;
unsigned int b = 20;
unsigned int c = 30;
float d = -(int)((a*b)*(c/3));
printf("d = %f\n", d);
return 0;
}
Your whole calculation will be done unsigned so it is the same as
float d = -(2000u);
-2000 in unsigned int (assuming 32bits int) is 4294965295
this gets written in your float d. But as float can not save this exact number it gets saved as 4294965248.
As a rule of thumb you can say that float has a precision of 7 significant base 10 digits.
What is calculated is 2^32 - 2000 and then floating point precision does the rest.
If you instead use 3.0 this changes the types in your calculation as follows
float d = -((a*b)*(c/3.0));
float d = -((unsigned*unsigned)*(unsigned/double));
float d = -((unsigned)*(double));
float d = -(double);
leaving you with the correct negative value.
you need to cast the ints to floats
float d = -((a*b)*(c/3));
to
float d = -(((float)a*(float)b)*((float)c/3.0));
-((a*b)*(c/3)); is all performed in unsigned integer arithmetic, including the unary negation. Unary negation is well-defined for an unsigned type: mathematically the result is modulo 2N where N is the number of bits in unsigned int. When you assign that large number to the float, you encounter some loss of precision; the result, due to its binary magnitude, is the nearest number to the unsigned int that divides 2048.
If you change 3 to 3.0, then c / 3.0 is a double type, and the result of a * b is therefore converted to a double before being multiplied. This double is then assigned to a float, with the precision loss already observed.

When R.H.S have negative int and unsigned int outside the range of int in arithmetic operation

I apologize for the title since I had to somehow find a unique one.
Consider the code below:
#include<stdio.h>
int main(void)
{
int b = 2147483648; // To show the maximum value of int type here is 2147483647
printf("%d\n",b);
unsigned int a = 2147483650;
unsigned int c = a+(-1);
printf("%u\n",c);
}
The output of the above program when run on a 64 bit OS with gcc compiler is:
-2147483648
2147483649
Please see my understanding of the case:
Unsigned int a is outside the range of signed int type. In the R.H.S (-1) will converted to unsigned int since the operands are of different types. The result of converting -1 to unsigned int is:
-1 + (unsigned int MAX_UINT +1) = unsigned int MAX_UINT = 4294967295.
Now R.H.S will be:
unsigned int MAX_UINT + 2147483650
Now this looks like it is outside the range of unsigned int. I do not know how to proceed from here and it looks like even if I proceed with this explanation I will not reach the empirical output.
Please give a proper explanation.
PS: To know how int b = 2147483648 became -2147483648 is not my intention. I just added that line in the code so it is pretty clear that 2147483650
is outside the range of int.
2147483648 is not a 32-bit int, it is just above INT_MAX whose value is 2147483647 on such platforms.
int b = 2147483648; is implementation defined. On your platform, it seems to perform 32-bit wrap around, which is typical of two's complement architectures but not guaranteed by the C Standard.
As a consequence printf("%d\n", b); outputs -2147483648.
The rest of the code is perfectly defined on 32-bit systems, and the output 2147483649 is correct and expected. The fact that the OS by 64 bit plays a very subtle role in the evaluation steps but is mostly irrelevant to the actual result, which is fully defined by the C Standard.
Here are steps:
unsigned int a = 2147483650; no surprise here, a is an unsigned int and its initializer is either an int, a long int or a long long int depending on which of these types has at least 32 value bits. On Windows and 32-bit linux, it would be long long int whereas on 64-bit linux it would be long int. The value is truncated to 32-bit upon storing to the unsigned int variable.
You can verify these steps by adding this code:
printf("sizeof(2147483650) -> %d\n", (int)sizeof(2147483650));
printf(" sizeof(a) -> %d\n", (int)sizeof(a));
The second definition unsigned int c = a+(-1); undergoes the same steps:
c is defined as an unsigned int and its initializer is truncated to 32 bits when stored into c. The initializer is an addition:
the first term is an unsigned int with value 2147483650U.
the second term is a parenthesized expression with the unary negation of an int with value 1. Hence it is an int with value -1 as you correctly analyzed.
the second term is converted to unsigned int: conversion is performed modulo 232, hence the value is 4294967295U.
the addition is then performed using unsigned arithmetics, which is specified as taking place modulo the width of the unsigned int type, hence the result is an unsigned int with value 2147483649U, (6442450945 modulo 232)
This unsigned int value is stored into c and prints correctly with printf("%u\n", c); as 2147483649.
If the expression had been instead 2147483650 + (-1), the computation would have taken place in 64 bits signed arithmetics, with type long int or long long int depending on the architecture, with a result of 2147483649. This value would then be truncated to 32-bits when stored into c, hence the same value for c as 2147483649.
Note that the above steps do not depend on the actual representation of negative values. They are fully defined for all architectures, only the width of type int matters.
You can verify these steps with extra code. Here is a complete instrumented program to illustrate these steps:
#include <limits.h>
#include <stdio.h>
int main(void) {
printf("\n");
printf(" sizeof(int) -> %d\n", (int)sizeof(int));
printf(" sizeof(unsigned int) -> %d\n", (int)sizeof(unsigned int));
printf(" sizeof(long int) -> %d\n", (int)sizeof(long int));
printf(" sizeof(long long int) -> %d\n", (int)sizeof(long long int));
printf("\n");
int b = 2147483647; // To show the maximum value of int type here is 2147483647
printf(" int b = 2147483647;\n");
printf(" b -> %d\n",b);
printf(" sizeof(b) -> %d\n", (int)sizeof(b));
printf(" sizeof(2147483647) -> %d\n", (int)sizeof(2147483647));
printf(" sizeof(2147483648) -> %d\n", (int)sizeof(2147483648));
printf(" sizeof(2147483648U) -> %d\n", (int)sizeof(2147483648U));
printf("\n");
unsigned int a = 2147483650;
printf(" unsigned int a = 2147483650;\n");
printf(" a -> %u\n", a);
printf(" sizeof(2147483650U) -> %d\n", (int)sizeof(2147483650U));
printf(" sizeof(2147483650) -> %d\n", (int)sizeof(2147483650));
printf("\n");
unsigned int c = a+(-1);
printf(" unsigned int c = a+(-1);\n");
printf(" c -> %u\n", c);
printf(" sizeof(c) -> %d\n", (int)sizeof(c));
printf(" a+(-1) -> %u\n", a+(-1));
printf(" sizeof(a+(-1)) -> %d\n", (int)sizeof(a+(-1)));
#if LONG_MAX == 2147483647
printf(" 2147483650+(-1) -> %lld\n", 2147483650+(-1));
#else
printf(" 2147483650+(-1) -> %ld\n", 2147483650+(-1));
#endif
printf(" sizeof(2147483650+(-1)) -> %d\n", (int)sizeof(2147483650+(-1)));
printf(" 2147483650U+(-1) -> %u\n", 2147483650U+(-1));
printf("sizeof(2147483650U+(-1)) -> %d\n", (int)sizeof(2147483650U+(-1)));
printf("\n");
return 0;
}
Output:
sizeof(int) -> 4
sizeof(unsigned int) -> 4
sizeof(long int) -> 8
sizeof(long long int) -> 8
int b = 2147483647;
b -> 2147483647
sizeof(b) -> 4
sizeof(2147483647) -> 4
sizeof(2147483648) -> 8
sizeof(2147483648U) -> 4
unsigned int a = 2147483650;
a -> 2147483650
sizeof(2147483650U) -> 4
sizeof(2147483650) -> 8
unsigned int c = a+(-1);
c -> 2147483649
sizeof(c) -> 4
a+(-1) -> 2147483649
sizeof(a+(-1)) -> 4
2147483650+(-1) -> 2147483649
sizeof(2147483650+(-1)) -> 8
2147483650U+(-1) -> 2147483649
sizeof(2147483650U+(-1)) -> 4
int b = 2147483648;
printf("%d\n",b);
// -2147483648
Conversion of an integer (any signed or unsigned) that is outside the range of the target signed type:
... either the result is implementation-defined or an implementation-defined signal is raised. C11 ยง6.3.1.3 3
In your case with the signed integer 2147483648, the implementation-defined behavior appears to map the lowest 32-bits of the source 2147483648 to your int's 32-bits. This may not be the result with another compiler.
a+(-1) is the same as a + (-(1u)) same as a + (-1u + UINT_MAX + 1u) same as a + UINT_MAX. The addition overflows the unsigned range, yet unsigned overflow wraps around. So the sum is 2147483649 before the assignment. With the below code, there is no out of range conversion. The only conversion is signed 1 to unsigned 1 and long 2147483650 (or long long 2147483650) to unsigned 2147483650. Both in range conversions.
unsigned int a = 2147483650;
unsigned int c = a+(-1);
printf("%u\n",c);
// 2147483649
Look at it like this
2147483650 0x80000002
+ -1 +0xFFFFFFFF
---------- ----------
2147483649 0x80000001
Where does the 0xFFFFFFFF come from? Well, 0 is 0x00000000, and if you subtract 1 from that you get 0xFFFFFFFF because unsigned arithmetic is well-defined to "wrap".
Or taking your decimal version further, 0 - 1 is UINT_MAX because unsigned int wraps, and so does the sum.
your value 2147483650
UINT_MAX + 4294967295
----------
6442450945
modulo 2^32 % 4294967296
----------
2147483649

Hexdecimals in C

I'm confused. Why in this program a gives me 0xFFFFFFA0 but b gives me 0xA0? It's weird.
#include <stdio.h>
int main()
{
char a = 0xA0;
int b = 0xA0;
printf("a = %x\n", a);
printf("b = %x\n", b);
}
Default type of a is signed in char a = 0xA0; and in any signed data type whether its char of int you should be careful of sign bit, if sign bit is set means number will be negative and store as two's compliment way.
char a = 0xA0; /* only 1 byte for a but since sign bit is set,
it gets copied into remaining bytes also */
a => 1010 0000
|
this sign bit gets copied
1111 1111 1111 1111 1111 1111 1010 0000
f f f f f f A 0
In case of int b = 0xA0; sign bit(31st bit) is 0 so what ever it contains i.e 0xA0 will be printed.
Let's take this step-by-step.
char a = 0xA0;
0xA0 in an integer constant with a value of 160 and type int.
In OP's case, a char is encoded like a signed char with an 8-bit range. 160 is more than the maximum 8-bit char and so assigning an out-of-range value to a some signed integer type is implementation defined behavior. In OP's case, the value "wrapped around" and a took on the value of 160 - 256 or -96.
// Try
printf("a = %d\n", a);
With printf() (a variadic function), char a it passed to the ... part and so goes though the usual integer promotions to an int and retains the same value.
printf("a = %x\n", a);
// is just like
printf("a = %x\n", -96);
printf("a = %x\n", a);
With printf(), "%x" expect an unsigned or an int with a value in the non-negative range. With int and -96, it is neither and so the output is undefined behavior.
A typical undefined behavior is this case is to interpret the passed bit pattern as an unsigned. The bit pattern of int -96, as a 32-bit int is 0xFFFFFFA0.
Moral of the story:
Enable a compile warnings. A good compiler would warn about both char a = 0xA0; and printf("a = %x\n", a);
Do not rely on undefined behavior.

How do I sign extend and then find the value of the unsigned binary number in C?

I have a variable declared as an int
int a = -3;
I want the twos' complement values sign extended to 16 bits. So, it becomes: 1111 1111 1111 1101 and then find the unsigned value of this number, which would be 65533 (I believe).
In other words, I want to go from -3 to 65533.
Following this answer: Sign extension from 16 to 32 bits in C I'm stuck on the first step. Here's a shortened version of my code:
#include <stdio.h>
#include <string.h>
int main () {
int s = -3;
printf("%x\n", s);
s = (int16_t)s;
printf("%x\n", s);
int16_t i = s;
printf("%x\n", i);
return(0);
}
I compile with gcc test.c and all three printf statements give "fffffffd"
Do you know why the cast isn't working and perhaps any better solutions to the original problem?
Where you appear to be struggling with the issue is understanding just exactly what bits you are dealing with in interpreting the bits as signed or unsigned or as exact-width types.
How do I sign extend and then find the value of the unsigned binary
number in C?
Answer: you don't -- the bits never change....
When you declare int a = -3;, the bits are set in memory. Thereafter, unless you change them, they are the exact same 32-bits (or whatever sizeof a is on your hardware).
The key to understanding sign-extension is it only applies when interpreting a negative value under a two's complement system when casting or assigning to a larger-size type. Otherwise, you are not extending anything, you are just interpreting the bits as a different type.
A short example for your problem will illustrate. Here int a = -3; is declared (defined) and the bits of a thereafter never change. However, you can interpret those bits (or by lose analogy look at them from a different viewpoint) and use those bits as short, unsigned short, int16_t or uint16_t and in all unsigned cases, interpret them as a hexadecimal value, e.g.
#include <stdio.h>
#include <stdint.h>
#ifdef __GNUC__
#include <inttypes.h>
#endif
int main (void) {
int a = -3;
printf ("a (as int) : %d\n"
"a (as short) : %hd\n"
"a (as unsigned short) : %hu\n"
"a (as unsigned short hex) : 0x%0x\n"
"a (as PRId16) : %" PRId16 "\n"
"a (as PRIu16) : %" PRIu16 "\n"
"a (as PRIx16) : 0x%" PRIx16 "\n",
a, (short)a, (unsigned short)a, (unsigned short)a,
(int16_t)a, (uint16_t)a, (uint16_t)a);
return 0;
}
Example Use/Output
$ ./bin/exact3
a (as int) : -3
a (as short) : -3
a (as unsigned short) : 65533
a (as unsigned short hex) : 0xfffd
a (as PRId16) : -3
a (as PRIu16) : 65533
a (as PRIx16) : 0xfffd
Look things over, and look at all the answers, and let us know if you have any further questions.
Your code causes undefined behaviour by using the wrong format specifier for the argument type in printf.
Here is some correct code:
#include <stdio.h>
int main(void)
{
int s = -3;
uint16_t u = s; // u now has the value 65533
printf("%u\n", (unsigned int)u);
printf("%x\n", (unsigned int)u);
}
The code to printf a uint16_t is slightly complicated, it's simpler to cast to unsigned int and use %u or %x which are specifiers for unsigned int.
fffffffd is the correct two's complement value it's just being printed in hex
use %d in your printf statements
#include <stdio.h>
#include <string.h>
int main () {
int s = -3;
printf("%d\n", s);
s = (int16_t)s;
printf("%d\n", s);
int16_t i = s;
printf("%d\n", i);
return(0);
}
and you should see that 65533 value
In C casting signed value to a wider type automatically extends its sign.
To get a complement value you need to cast your value to appropriate unsigned type:
#include <stdio.h>
#include <stdint.h>
int main ()
{
int s = -3;
printf("%x\n", s);
int16_t s16 = (int16_t)s;
printf("%hd\n", s16);
uint16_t c16 = (uint16_t)s16;
printf("%hu\n", c16);
}
The output I get:
fffffffd
-3
65533

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