Why is the unsigned variable storing negative value? [duplicate] - c

This question already has answers here:
What happens if I assign a negative value to an unsigned variable?
(7 answers)
Assigning negative numbers to an unsigned int?
(14 answers)
Closed 3 years ago.
I have assigned -1 to unsigned int and assuming it would produce an error I compiled the code, much to my astonishment it didn't. I can't understand the reason behind it.
I have tried printing the values to check them manually, but it always shows -1.
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
int main(int argc, char *argv[]) {
unsigned int x = -1;
printf("%u\n", x);
int y = -1;
printf("%d\n", y);
if (x == y) {
printf("\nsame");
} else {
printf("n s");
}
return 0;
}
the expected result would have been an error or a warning
but it compiled as is.

It works because this:
unsigned int x = -1;
causes the int-typed literal -1 to be converted to an unsigned int which is a standard, well-specified, conversion. The draft C11 spec says:
6.3.1.3 Signed and unsigned integers
1 When a value with integer type is converted to another integer type other than
_Bool, if the value can be represented by the new type, it is unchanged.
2 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.60)
The latter is what is happening here, so assuming 32-bit integers 232 is being added, making the result 0xffffffff.
I don't believe that the printf() with %u prints -1, that would be a rather major bug.

This is allowed by the standard. When you assign -1 to the unsigned type, conceptually at least, the value is converted to a number that can be represented by the repeated addition of 2n where n is the number of bits in that type.
This conversion also happens to the signed type in the comparison x == y (that comparison takes place in unsigned arithmetic since one of the variables is an unsigned type).

Related

Why the value of signed char is greater than the unsigned int [duplicate]

This question already has answers here:
Comparison operation on unsigned and signed integers
(7 answers)
Closed 1 year ago.
#include <stdio.h>
int main() {
unsigned int i = 23;
signed char c = -23;
if (i<c)
puts("TRUE");
return 0;
}
Why the output of the following program is TRUE, even though I have used signed char which can store from -128 to 127.
Your i < c comparison has operands of two different types, so the operand with the smaller type (lower rank) is converted to the type of the other. In this case, as -23 cannot be represented as an unsigned int, and following the "usual arithmetic conversions," it will end up with a value considerably greater than +23 (actually, UINT_MAX + 1 - 23), according to Paragraph #2 in the following excerpt from this (Draft) C11 Standard:
6.3.1.3 Signed and unsigned integers
1    When a value with integer type is converted to another integer type other than _Bool, if the value can be represented by the new type, it is unchanged.
2    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.
3    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.
You can see this conversion in action by assigning c to a separate unsigned int and printing its value, as in the following code. Assuming a 32-bit unsigned int, you will likely see a value of 4294967273 (which is, indeed, greater than 23).
#include <stdio.h>
int main()
{
unsigned int i = 23;
signed char c = -23;
unsigned int uc = c; // Add a diagnostic line ...
printf("%u\n", uc); // ... and show the value being used in the comparison
if (i < c) {
printf("TRUE");
}
return 0;
}
Note: The relative size of the two variables (i and c) here is something of a red herring; even if you declare c as signed int c = -23;, you will still get the same result, due to the Usual Arithmetic Conversions (link courtesy of Jonathan Leffler's comment) – note that a signed int cannot represent all possible values of an unsigned int, so the very last of the 'hollow' bullets will come into play.
In order to make the comparison, the smallest variable (char, 8 bit) must be promoted to the size and signedness of the larger one (integer, 32 bit). But in so doing, -23 becomes 4294967273. Which is much more than 23.
If you compare c with a signed integer, the sign promotion causes no change and the test behaves as expected.

Information lost with type conversion in C [duplicate]

This question already has answers here:
assigning 128 to char variable in c
(3 answers)
Closed 4 years ago.
#include <stdio.h>
int main(int argc, char const *argv[])
{
int x = 128;
char y = x;
int z = y;
printf("%d\n", z);
return 0;
}
i don't understand why this program prints -128.
i have tried to convert 128 in binary base but i'm still confused on how the C compiler convert int to char and char to int.
Note : in my machine sizeof(char) = 1 and sizeof(int) = 4
Assuming a char is signed and 8 bits, its range is -128 to 127 which means the value 128 is out of range for a char. So the value is converted in a implementation-defined manner. In the case of gcc, the result is reduced modulo 28 to become in range.
What this basically means is that the low-order byte of the int value 128 is assigned to the char variable. 128 in hex as 32-bit is 0x00000080, so 0x80 is assigned to y. Assuming 2's compliment representation, this represents the value -128. When this value is then assigned to z, which is an int, that value can be represented in an int, so that's what gets assigned to it, and its representation is 0xffffff80.
C standard does not specify whether char is signed or unsigned. In fact, assigning a char type a value outside of the basic execution character set is implementation defined. You can probably use the macros in <limits.h> to verify.
I suspect on your system char is signed, which makes the max value 127. Signed interger overflow is undefined. So no guarantess on the output. In this case, it looks like it wraps around.

why sizeof type compared with integer returns false [duplicate]

This question already has answers here:
sizeof() operator in if-statement
(5 answers)
Why is sizeof(int) less than -1? [duplicate]
(3 answers)
void main() { if(sizeof(int) > -1) printf("true"); else printf("false"); ; [duplicate]
(3 answers)
Why does this if condition fail for comparison of negative and positive integers [duplicate]
(6 answers)
Closed 4 years ago.
one strange behaviour I noticed in below code.
#include<stdio.h>
#include <stdbool.h>
int main()
{
int x = sizeof(int) > -1;
bool z = sizeof(int);
printf("x is %d \t z is %d \n",x,z);
if(sizeof(int)>-1)
{
printf("true\n");
}
else
printf("false\n");
}
Why int x is zero when sizeof(int) > -1 is true and the expected output should be 1.
GCC compiler Warning say's :
prog.c: In function 'main':
prog.c:6:21: warning: comparison of integer expressions of different signedness: 'long unsigned int' and 'int' [-Wsign-compare]
int x = sizeof(int) > -1;
^
prog.c:11:15: warning: comparison of integer expressions of different signedness: 'long unsigned int' and 'int' [-Wsign-compare]
if(sizeof(int)>-1)
So, you are comparing a signed int and an unsigned long int. When -1 is converted to unsigned long int the result is the maximal possible unsigned long int value (same as ULONG_MAX).
C $6.3.1.3, paragraph 2:
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.
For more information, read cppreference.
The sizeof operator yields not an int but size_t which is an unsigned integer type. When you compare a signed integer like -1 to an unsigned integer you will end up comparing the wrong values.
Do the following changes and the code will work as expected.
#include<stdio.h>
#include <stdbool.h>
int main()
{
int x = (int)sizeof(int) > -1;
bool z = sizeof(int);
printf("x is %d \t z is %d \n",x,z);
if((int)sizeof(int) > -1)
{
printf("true\n");
}
else
printf("false\n");
}
Output:
x is 1 z is 1
true
sizeof operator returns a type of size_t
The size_t type is an unsigned type. usually unsigned int
If you compare an unsigned int with -1 then by the integer promotion rules (Signed to unsigned conversion in C - is it always safe?), both of them will be converted to unsigned.
So -1 will be converted to 65535 and the equation 4>65535 will result in zero.
Difference between signed and unsigned integer types (which includes char) is that negative values are represented by most significant bit set to 1. On most platform the magnitude is represented by binary complement in that case. E.g. for char:
10000001: -(1)0000000 * 01111111 = -127
We should take 00000001, substract 1 from it and invert all bits except sign to get the value.
Now, during comparison signed values treated as unsigned, if other argument is unsigned. There are historical and practical reasons for that, e.g. to avoid ambiguity in character comparison when compiling legacy code. Traditionally all string in C were char* not unsigned char*.
10000001 as unsigned char equals to 129.
So, according to this program -1 is greater than 1.
#include <iostream>
int a = -1;
unsigned int b = 1;
int main(int argc, char** argv)
{
if(b < a) std::cout << "The world is mad.\n";
if(a > b) std::cout << "Yes, it is.\n";
return 0;
}
You always should look out for warning about comparison as well as about "possible data loss". Those are very common source of bug in programs.

Why x is promoted to unsigned int? [duplicate]

This question already has answers here:
Why is a negative int greater than unsigned int? [duplicate]
(6 answers)
Closed 5 years ago.
Given that code :
int main(void) {
long x = -1;
if (x < sizeof(x)) {
printf("OK\n");
}
else {
printf("Not Ok\n");
}
return 0;
}
Prints:
Not Ok
I have read about usual arithmetic conversions, and from what i understood that if we have a comparison between two operands with different data types, the compiler invokes a data coercion on the operand which is narrower than the other operand, which will convert the the sizeof(x) into unsigned int to match the other operand, any thoughts?
Aside question:
I tried to do casting size(x) as int in the comparison expression as:
if(x < (int) size(x))
It prints Ok, which I find very strange!
You should never compare a signed number to an unsigned number. Add a compiler switch to warn you about this.
Here, in your case, x will be converted to unsigned, -1 becomes SIZE_MAX (the largest number a that std::size_t can hold). It is because sizeof returns an unsigned number (it returns std::size_t, which is unsigned)
The other thing that could happen, but don't happen in practice is that if sizeof(long)>sizeof(std::size_t) then sizeof(x) would be converted to long, so your program would print OK.

Comparision between a signed/unsigned value with a negative value

Program 1:
#include <stdio.h>
int main()
{
if (sizeof(int) > -1)
printf("Yes");
else
printf("No");
return 0;
}
Output : No
Program 2:
#include <stdio.h>
int main()
{
if (2 > -1)
printf("Yes");
else
printf("No");
return 0;
}
Output: Yes
Questions:
What is the difference between program 1 and program 2?
Why sizeof(int) is considered as unsigned?
Why is 2 in program 2 considered as signed?
It is common issue with usual arithmetic conversions between signed and unsigned integers. The sizeof operator returns value of type size_t, that is some implementation-defined unsigned integer type, defined in <stddef.h> (see also this answer).
Integer constant -1 is of type int. When size_t is implemented as "at least" unsigned int (which is very likely to happen in your case), then both operands of binary operator < are converted to unsigned type. Unsigned value cannot be negative, hence -1 is conveted into a large number.
The type of the value returned by the sizeof operator is size_t, which is specified to be an unsigned type (often equivalent to unsigned long).
Simple plain integer literals, like 2 or -1 are always of type int, and int is signed.
If you want an unsigned integer literal, you have to add the U suffix, like 2U.
This is because the sizeof operator returns a value in size_t. This is supposed to be an unsigned type, often implemented as unsigned int.
The number 2 by itself is an int, not unsigned int.

Resources