[c] Convert unsigned int to signed int C

I am trying to convert 65529 from an unsigned int to a signed int. I tried doing a cast like this:

unsigned int x = 65529;
int y = (int) x;

But y is still returning 65529 when it should return -7. Why is that?

This question is related to c int unsigned-integer

The answer is


@Mysticial got it. A short is usually 16-bit and will illustrate the answer:

int main()  
{
    unsigned int x = 65529;
    int y = (int) x;
    printf("%d\n", y);

    unsigned short z = 65529;
    short zz = (short)z;
    printf("%d\n", zz);
}

65529
-7
Press any key to continue . . .


A little more detail. It's all about how signed numbers are stored in memory. Do a search for twos-complement notation for more detail, but here are the basics.

So let's look at 65529 decimal. It can be represented as FFF9h in hexadecimal. We can also represent that in binary as:

11111111 11111001

When we declare short zz = 65529;, the compiler interprets 65529 as a signed value. In twos-complement notation, the top bit signifies whether a signed value is positive or negative. In this case, you can see the top bit is a 1, so it is treated as a negative number. That's why it prints out -7.

For an unsigned short, we don't care about sign since it's unsigned. So when we print it out using %d, we use all 16 bits, so it's interpreted as 65529.


I know it's an old question, but it's a good one, so how about this?

unsigned short int x = 65529U;
short int y = *(short int*)&x;

printf("%d\n", y);

The representation of the values 65529u and -7 are identical for 16-bit ints. Only the interpretation of the bits is different.

For larger ints and these values, you need to sign extend; one way is with logical operations

int y = (int )(x | 0xffff0000u); // assumes 16 to 32 extension, x is > 32767

If speed is not an issue, or divide is fast on your processor,

int y = ((int ) (x * 65536u)) / 65536;

The multiply shifts left 16 bits (again, assuming 16 to 32 extension), and the divide shifts right maintaining the sign.


You are expecting that your int type is 16 bit wide, in which case you'd indeed get a negative value. But most likely it's 32 bits wide, so a signed int can represent 65529 just fine. You can check this by printing sizeof(int).


To understand why, you need to know that the CPU represents signed numbers using the two's complement (maybe not all, but many).

    byte n = 1; //0000 0001 =  1
    n = ~n + 1; //1111 1110 + 0000 0001 = 1111 1111 = -1

And also, that the type int and unsigned int can be of different sized depending on your CPU. When doing specific stuff like this:

   #include <stdint.h>
   int8_t ibyte;
   uint8_t ubyte;
   int16_t iword;
   //......

Since converting unsigned values use to represent positive numbers converting it can be done by setting the most significant bit to 0. Therefore a program will not interpret that as a Two`s complement value. One caveat is that this will lose information for numbers that near max of the unsigned type.

template <typename TUnsigned, typename TSinged>
TSinged UnsignedToSigned(TUnsigned val)
{
    return val & ~(1 << ((sizeof(TUnsigned) * 8) - 1));
}

I know this is an old question, but I think the responders may have misinterpreted it. I think what was intended was to convert a 16-digit bit sequence received as an unsigned integer (technically, an unsigned short) into a signed integer. This might happen (it recently did to me) when you need to convert something received from a network from network byte order to host byte order. In that case, use a union:

unsigned short value_from_network;
unsigned short host_val = ntohs(value_from_network);
// Now suppose host_val is 65529.
union SignedUnsigned {
  short          s_int;
  unsigned short us_int;
};
SignedUnsigned su;
su.us_int = host_val;
short minus_seven = su.s_int;

And now minus_seven has the value -7.


To answer the question posted in the comment above - try something like this:

unsigned short int x = 65529U;
short int y = (short int)x;

printf("%d\n", y);

or

unsigned short int x = 65529U;
short int y = 0;

memcpy(&y, &x, sizeof(short int);
printf("%d\n", y);

Examples related to c

conflicting types for 'outchar' Can't compile C program on a Mac after upgrade to Mojave Program to find largest and second largest number in array Prime numbers between 1 to 100 in C Programming Language In c, in bool, true == 1 and false == 0? How I can print to stderr in C? Visual Studio Code includePath "error: assignment to expression with array type error" when I assign a struct field (C) Compiling an application for use in highly radioactive environments How can you print multiple variables inside a string using printf?

Examples related to int

How can I convert a char to int in Java? How to take the nth digit of a number in python "OverflowError: Python int too large to convert to C long" on windows but not mac Pandas: Subtracting two date columns and the result being an integer Convert bytes to int? How to round a Double to the nearest Int in swift? Leading zeros for Int in Swift C convert floating point to int Convert Int to String in Swift Converting String to Int with Swift

Examples related to unsigned-integer

How can I get the size of an std::vector as an int? Convert unsigned int to signed int C Calculating bits required to store decimal number What is the difference between signed and unsigned int What is the benefit of zerofill in MySQL? What is a difference between unsigned int and signed int in C? A warning - comparison between signed and unsigned integer expressions