Take care of C pitfalls, they may be harmful (part1)

Have you experienced staying up checking your code for hours or maybe for days for something wrong, but you can’t figure out where the problem is.

crazy-images-6.jpg

Calm down, most of us have been through this many times. And in this article and the upcoming articles we will introduce the most known and harmful C language pitfalls that we can take care of them and avoid their effect.

This article will be about “Type conversion”, which is a very tricky topic and we will learn it’s disadvantages and how to write a safe code.

Type conversion(implicit conversion):

The type conversion is converting different data types in an expression to the same type to be easy to be processed, for example:

int x = 1;
float y = 3.5;
float result;
result = x + y;
printf("The result = %f",result);

We all know that the result is 4.5 but there is something happens behind the scene.
For those who don’t know that the float numbers are stored in memory in a different representation ‘IEEE 754’,  or known as ‘Mantissa‘, so how those different type are added together? To know we will have a look at the assembly code “IAR compiled”

type_conversion

The first highlighted line is a call to a function that converts x from integer to float representation, and the second highlighted line is a call to function that add two float numbers.
The type conversion has an order according to C standard(usual arithmetic conversions) :

c-usual-arithmetic-conversion

Untitled (1)

Easy, right? So where is the problem then? Let’s talk first about a special kind of type conversion called “type promotion” or “integer promotion”.

Integer promotion:

Promotions are commonly used with types smaller than the native type of the target platform’s arithmetic logic unit (ALU)(the size of registers), before arithmetic and logical operations, to make such operations possible, or more efficient if the ALU can work with more than one type.

C and C++ perform such promotion for objects of boolean, character, enumeration, and short integer types which are promoted to int, and for objects of type float, which are promoted to double.
Unlike some other type conversions, promotions never lose precision or modify the value stored in the object.

Let’s take an example:

unsigned char x = 1;
unsigned char y = 3;
unsigned char result;
result = x + y;
printf("The result = %d",result);

It’s a simple code add two 8-bits variable x and y and the result will be 4, nothing strange.

Assume we use a 32-bit processor, so the ALU can deal with 32-bit value found in it’s registers, and for the forgoing code the the addition operation will occur between 32-bit variable (integer size), or we can say the type char has been promoted to integer type.

Up till now every this is OK, the problem will occur when comparing between different signed variables (signed and unsigned) for example:

singed char x = 0xff;
unsigned char y = 0xff;
if(x==y)
{
  printf("x and y are equal");
}
else
{
  printf("x and y are not equal");
}

What do you think the result will be?  x and y are equal because they both hold the value 0xff, or they are not equal because x is equal to 255 and y is equal to -1.
The result will be “x and y are not equal” but how did the compiler deal with it?
The compiler will first promote the two variable to integer but signed or unsigned? There is a rule according to C99 standard

c99_2.PNG

The value of x and y can be presented in signed int so the x and y are promoted to signed integer. Let’s print the value of x and y in an integer representation and see the difference after promotion.

singed char x = 0xff;
unsigned char y = 0xff;
printf("x in integer representation = 0x%08x\n",x); // print as hexadecimal
printf("y in integer representation = 0x%08x\n",y); // print as hexadeciaml

out

Do you see the difference? the y has been sign extended to keep the sign in the 32-bit representation so 0x000000ff is not equal to 0xffffffff 😀

Let’s take another example:

int x = 5;
unsigned int y = -1; // 0xffffffff in hexadecimal
 if(y<x)
 {
 printf("y is less than x");
 }
 else
 {
 printf("y is not less than x");
 }

out2

The output is not what we expected, because the compiler due to the promotion rule find the the value of unsigned int can’t fit in signed int so it converted the type of signed int to unsigned (actually it’s not a conversion, it’s just the way the compiler will use to compare between the two variables) so (as unsigned value) the value of 0xffffffff  is not less than 0x00000005

Think about the upcoming code and what will the output?and what would be the output if one or both of x and y are unsigned int?

unsigned x = 5;
unsigned y = 0;
 if((y-x) < 0)
{
printf("y-x is less than 0");
}
else
{
printf("y-x is greater than 0");
}

We experienced that mixing signed and unsigned types can results into a different behavior other than we expect, so what should we do to avoid these pitfalls?
The answer is explicit conversion (explicit casting) to force the compiler to behave as we aim to.

In the upcoming articles we will talk about casting , how to use it to write a safe code, and the disadvantages of using casing. Stay tuned 🙂

 

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s