Closer look at signed and unsigned integers in C (signed vs unsigned)

what is difference between signed and unsigned integers?

Many times I have found that people make mistakes when they are using signed and unsigned integers. Sometimes the basic mistake can create hidden issues and waist you’re a lot of time searching for the bugs. I know, everybody is aware of the signed and unsigned integer but still, they are making mistakes that’s why in this article I am explaining some important points and questions regarding the signed and unsigned int in C.

An integer has no fractional part, in C language integer is generally represented by short, int, and long. The size of the long must be at least 32 bits, and the size of the int and short must be at least 16 bits but the size of the short no longer than int.

We can arrange short, int, and long in ascending order in the following way:

sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long) (only C99)

 

I am not interested here to explain data type so I am coming on points with basic viral questions.

Size of the integer depends on what?

The C standard is explained that the minimum size of the integer should be 16 bits. Some programing languages is explained that the size of the integer is implementation-dependent but portable programs shouldn’t depend on it.

Primarily the size of an integer depends on the type of compiler which has been written by the compiler writer for the underlying processor. You can see compilers merrily changing the size of integers according to convenience and underlying architectures. So it is my recommendation to use the C99 integer data types ( uin8_t, uin16_t, uin32_t ..) in place of standard int.

For learning more, you can signup for the free trial of this popular c video course by Kenny Kerr.

C tutorial

Are integers signed or unsigned?

According to C standard, the integer data type is by default signed. So it is the reason an integer variable, can store both positive and negative value.

 

What is the difference between unsigned int and signed int in C?

The signed and unsigned integer type has the same storage (according to the standard at least 16 bits) and alignment but still, there is a lot of difference between them, in bellows lines, I am describing some difference between the signed and unsigned integer.

  • A signed integer can store the positive and negative value both but besides it unsigned integer can only store the positive value.
  • The range of nonnegative values of a signed integer type is a sub-range of the corresponding unsigned integer type.
    For example,
//Assuming the size of the integer is 2 bytes.

signed int                                           -32768 to +32767

unsigned int                                         0 to 65535
  • When computing the unsigned integer, it never gets overflow because if the computation result is greater than the largest value of the unsigned integer type, it is reduced modulo the number that is one greater than the largest value that can be represented by the resulting type.

For example,

Computational Result  % (Largest value of the unsigned integer+1)

  • Overflow of the signed integer is undefined.
  • If Data is signed type negative value, the right shifting operation of Data is implementation-dependent but for the unsigned type, it would be Data/ 2pos.
  • If Data is signed type negative value, the left shifting operation of Data shows the undefined behavior but for the unsigned type, it would be Data x 2pos.

 

How do I convert a signed integer to an unsigned integer?

It is a basic question, generally asked by people on the internet but really it is very confusing and sometimes kills your mind. In the C language compiler perform automatic (implicit ) casting but some compiler gives the warning so every time we need to cast explicitly using the parenthesis to convert one type into the other type.

Let’s take an example,

int iData = 17;
unsigned int uiData = (unsigned int)iData;

Here I am not interested to know how to convert signed and unsigned integers vice versa but I am interested to know what happens if I am converting a signed integer to an unsigned integer or unsigned integer to an signed integer. For a better understanding, I am taking a few examples and seeing what happens if converting signed and unsigned to each other.

Converting a positive signed number to the unsigned integer:

 

#include <stdio.h>

int main(void)
{
    int  iData = 27;

    unsigned int uiData = (unsigned int)iData;

    printf("%u\n",uiData);

    return 0;
}

 

Output: 27

Explanation:  As per the C99 standard, when a value of integer type is converted to another type (except _Bool (C99))  and if the value can be represented by the new type then it will be unchanged.

 

Converting a negative signed integer to an unsigned integer:

If you have a variable of type signed int, and it contains a negative value such as -6 then how do you convert this to an unsigned data type, and what exactly happens if you perform a cast?

The answer to this question is that nothing happens because according to the C99 standard 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.

#include <stdio.h>

int main(void)
{
    int iData = -6;

    unsigned int uiData = (unsigned int)iData;

    printf("0x%x\n",uiData);

    return 0;
}

Output: 0xfffffffa

In the above example, I am assuming the size of the integer is 4 bytes (32 bit). Let us assume that the compiler represents a signed negative integer number in 2’s complement notation (This is the norm but not mentioned by the C standard) when casting the negative integer number then no bits will be changed only compiler treat the stored bits as the unsigned integer.

So if we analyze the above example, the binary representation of -6 will be 0xFFFFFFFA (4294967290). This value comes under the range of unsigned int so after the casting of this value there are no specific effects that happened on the bits.

See the below image for a better understanding which describes the above scenario and the compiler represents -6 in 2’s complement notation.

conversion signed unsigned in C

 

 

If your compiler represents signed integers (assume 4 bytes) using 2’s complement notation, the below image help to understand how the signed integer will be represented.

Negative Number Representation

 

Note: Need to remember, it is not the fact that casting -6 to an unsigned type will be 0xFFFFFFFA. Whether it does or not depends entirely on how the compiler chooses to represent negative numbers.

 

Converting an unsigned integer to signed integer type:

As per the C99 standard if 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.

Let’s take an example to understand the above statement.

In the below example, I am assuming that the size of the integer is 4byte (32bit). I am creating an unsigned integer variable whose value is 19891992, the assigned value is in the range of the signed integer variable. So if we converting the unsigned integer value to the signed integer variable there will be no effect reflect.

#include <stdio.h>

int main(void)
{
    unsigned int  uiData = 19891992;

    signed int iData = (signed int)uiData;

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

    return 0;
}

 Output: 19891992

In another example, I am assigning the max value to the unsigned integer variable, when converting unsigned integer to the signed integer then the value is the out of the range of signed integer. The result value will be implementation-dependent.

#include <stdio.h>

int main(void)
{
    unsigned int  uiData = 4294967295;

    printf("%u\n",uiData);

    signed int iData = (signed int)uiData;

    printf("%u\n",iData);

    return 0;
}

Output: 4294967295
4294967295

 

Who is more efficient signed int or unsigned int?

Basically In my view unsigned int is far better than signed int, the behavior of unsigned int is well documented by the c standard but in some scenarios behavior of signed int is not defined.

Below I am discussing few points in favor of unsigned int.

  • The overflow of unsigned int is fully defined by the c standard community but not defined for the signed int.
  • When we will shift the signed negative value then its results depend on the implementation.
  • The range of unsigned int is larger than the range of the signed int.
  • The modulus operation is almost defined for the unsigned int.
  • Generally in the embedded system port and register deal with unsigned int because the value of the register and port treated as unsigned entities.
  • Using the unsigned int we can reduce some conditional statements.

For example,
if you have created a function that contains the lookup table, the arguments of the function should be unsigned integer type because of array index always a positive number.

Generally, when we create a lookup table we need to check the index of the lookup table because if it goes beyond the boundary then your code can crash. The function which contains the lookup table if the argument of that function is signed integer type then you have to put one more condition to check the index of lookup table because index should be greater or equal to zero.

Function with the signed integer as arguments:

void JumpTable (int index)
{
    if ((index >= 0) && (index < ARRAY_SIZE))
    {
      //Lookuptable
    }
}

In above code snippet, I have to put two conditions because the argument of the function is signed integer type.

 

Function with the unsigned integer as arguments:

void JumpTable (unsigned int index)
{
    if (index < ARRAY_SIZE)
    {
        //Lookuptable
    }
}

In above example, the function contains unsigned integer as arguments then there is no need to put two conditions because the value of unsigned int never goes less than zero.

 

When need to use signed int?

I am mentioning here some scenario where we need to use the signed int in place of the unsigned int.

  • When dealing with library function that has required int as arguments.
  • When performing the arithmetic operation then taking signed integer is beneficial.
  • When in a program you need to assign the negative integer value.

When should I use unsigned int in C?

When you are dealing with bit values or performing a bitwise operation like bit masking or bit-shifting then you should use unsigned int. Bit shifting of negative integer gives you undefined or implementation-defined output. In simple words, you should use the unsigned int until you do not require the signed int.

 

What happens if mixed signed and unsigned int?

If we mixed signed and unsigned int in the program then it can create issues because as per the c standard if we perform the arithmetic operation on a signed and unsigned number then the resultant value can be implementation dependent or undefined in some scenarios.

In C99, integer promotion is clearly defined that If an int can represent all values of the original type, the value is converted to an int, otherwise, it is converted to an unsigned int. All other types are unchanged by the integer promotions.

Note: My advice is that never mixed the signed and unsigned and always enable the warning option in your IDE.

See the below program and think the output of,

#include <stdio.h>

int main(void)
{
    unsigned int uiData = 2;
    int iData = -20;

    if(iData + uiData > 6)
    {
        printf("%s\n", "a+b > 6");
    }
    else
    {
        printf("%s\n", "a+b < 6");
    }

    return 0;
}

If you are familiar with integer promotion then, of course, you know the answer either you need to read the integer promotion. So it is my recommendation when you performed an arithmetic operation where the operands are signed and unsigned then carefully perform the operation either you will get the undefined result.

Below I am mentioning a few points, you need to take care of these points before performing the arithmetic operation.

  • If the value of the signed integer is negative then you have to take care before performing shifting and arithmetic operation.
  • If the value of the unsigned integer is greater than the maximum value that is represented by the signed integer.
  • The integer promotion rules can create a problem if you are not careful.

Your opinion matters

Although here I have tried to discuss a lot of points regarding the signed and unsigned integers I would like to know your opinion of the issues which you have faced related to signed and unsigned integers. So please don’t forget to write a comment in the comment box.

Recommended Post



10 comments

  1. Very simple. Never use signed types unless you expect or require negative values. For example, for loop iteration often runs from zero to some positive limit. Why would you ever declare the loop iteration variable an int? Unsigned or size_t tells the reader more clearly your intent.

    1. Yes agreed, but I saw many people used signed int with array index and in loops.In my previous project, I saw that some my colleagues used signed int without any requirements in math engine and compare signed and unsigned int, the compiler throws the warning but they just avoid it that is the reason I have written an article on signed and unsigned int.

  2. >>”The range of unsigned int is larger than the range of the signed int”
    I’m not agree. The range is equal for int and uint.

    >> printf(“%u\n”,iData);
    Also if you want to print int variable, you should use “%i” or “%d”.
    When you use “%u” the compiler casts the value back to unsigned int.

  3. “The range is equal for int and uint.” – I mean: the count of the possible values (that can be stored in the int or uint variable) is equal.

  4. very nice,simple and clear tutorial to learn for embedded c engineers thank you so much.
    I would like to ask you can you please share STM32 micro controller any related documents
    or sample codes for UART,SPI,I2C and etc.

    Thank you so much in advance

  5. If I try to convert a positive unsigned integer in a signed integer, I have as output the negative correspondant of my number.
    Why does it happens? If anyone could help me, I thank you.

Leave a Reply

Your email address will not be published. Required fields are marked *