One of the most important concept in programming is the variable. The variable can be seen as the “place” to store “things” as: numerical values, characters, text strings, memory addresses, etc. There are two main concepts regarding variables. The fist concept is the declaration of the variable, which basically means setting its data type. The second concept is the definition of the variable, which means setting its content.
In the C programming language every variable used in the source code needs to be declared by setting its data type. By assigning a certain data type to a variable we define several aspects linked to the variable:
- the memory size to be allocated to store the content of the variable
- the types of operations that can be performed on the variable
- the restrictions which are applied in terms of operations
By the end of this tutorial the reader will know:
- what is the significance of a data type
- how to declare and define a variable
- which are the properties of the standard data types
- what is integer overflow
In the C programming language a variable is declared as:
unsigned int uiVar;
where:
uiVar
– is the name of the variable
unsigned
– keyword which defines that our variable is always positive (without the sign “-“)
int
– keyword which defines that our variable is an integer and has 4 bytes of memory allocated (for a 32-bit compiler)
The definition of the variable can be done in another line, but only after the declaration:
uiVar = 25;
Variables can be declared and defined in the same instruction:
unsigned int uiVar = 25;
The main data types in C programming language are:
- integer (fixed-point)
- floating-point
- void
Note: Depending on the type of the compiler (16-bit or 32-bit), the size and range of int
, short
and long
are different.
The void type has no value and unknown size. It’s mainly used for function definition as return type or argument of the function.
Fixed-point (integers)
The integer data type is also knows as fixed-point type. Variables declared as integers store only integer numbers (e.g. -10
, 0
, 55
), they can not store real values (e.g 1.5
, 3.1416
).
In the example below we’ll declare a variable of type integer and we’ll assign a non integer value to it. With an if
statement we check if the value memorised in the variable is only the integer part of the value, if true we print a message.
#include <stdio.h> int main(void) { unsigned int uiVar; uiVar = 3.1416; if (uiVar == 3) { printf("Integer variables can not store decimals\n"); } return (0); }
As expected, the comparison uiVar==3
is true (since the message is displayed). This means that only the integer part of the number 3.1416
was memorised, since uiVar
was declared as an integer.
An integer can be signed
or unsigned
. This mean that it can contain both positive and negative numbers (signed
) or only positive numbers (unsigned
). Function of the number of bytes used to store the content, integer variables can be:
char
short
int
long
long long
For a 32-bit compiler, the differences between the integer data types are summarised in the table below:
Data type | # bytes | # bits | Minimum value | Maximum value | Formatprintf() | ||
char | 1 | 8 | -27 | -128 | 27-1 | 127 | %d |
signed char | 1 | 8 | -27 | -128 | 27-1 | 127 | %d |
unsigned char | 1 | 8 | 0 | 0 | 28-1 | 255 | %u |
short | 2 | 16 | -215 | -32768 | 215-1 | 32767 | %d |
signed short | 2 | 16 | -215 | -32768 | 215-1 | 32767 | %d |
unsigned short | 2 | 16 | 0 | 0 | 216-1 | 65535 | %u |
int | 4 | 32 | -231 | -2147483648 | 231-1 | 2147483647 | %d |
signed int | 4 | 32 | -231 | -2147483648 | 231-1 | 2147483647 | %d |
unsigned int | 4 | 32 | 0 | 0 | 232-1 | 4294967295 | %u |
long | 4 | 32 | -231 | -2147483648 | 231-1 | 2147483647 | %ld |
signed long | 4 | 32 | -231 | -2147483648 | 231-1 | 2147483647 | %ld |
unsigned long | 4 | 32 | 0 | 0 | 232-1 | 4294967295 | %lu |
long long | 8 | 64 | -263 | -9223372036854775808 | 263-1 | 9223372036854775807 | %lld |
signed long long | 8 | 64 | -263 | -9223372036854775808 | 263-1 | 9223372036854775807 | %lld |
unsigned long long | 8 | 64 | 0 | 0 | 264-1 | 18446744073709551615 | %llu |
Note: The number of bytes applies to both X86 (32-bit) and X64 (64-bit) compilers.
The usage of the signed
keyword is optional. If we don’t specify the sign, the default setting is signed
. For example int
is the same as signed int
and long
the same as signed long
.
Variables of type signed
use half of the range for negative values and the other half for positive values. When coding in C we need to pay attention if we really need to use signed
data types for our variables. If, for example, we define a variable to measure/calculate a fluid’s pressure, there is no point of using signed data type because the pressure is always positive. By using unsigned data types we double the range of the variable’s values.
Floating-point
Floating-point values are stored in the single-precision or double-precision format specified by the IEEE Standard 754. Real numbers contain also decimal point numbers so they need to be stored in floating-point variables.
There are three types of floating-point data types:
float
double
long double
float
data type is also knows as single-precision data type. double
is a enhanced version of float
, with bigger memory size, wider range and double-precision.
Data types | # bytes | Minimum value | Maximum value | Precision | Formatprintf() |
float | 4 | 1.2E-38 | 3.4E+38 | 6 decimal places | %f , %e |
double | 8 | 2.3E-308 | 1.7E+308 | 15 decimal places | %lf , %le |
long double | 10 | 3.4E-4932 | 1.1E+4932 | 19 decimal places | %Lf , %Le |
Data type limits
There are two header files (*.h
) which allows the user to gain precise information regarding the standard data types. To include the content of these header files, we need to write the following instructions at the beginning of our C source code file (*.c
):
#include <limits.h> #include <float.h>
In the macros defined in limits.h
header file we can find the limits (range) of the standard data types used in C programming language. The macros are constants with predefined names (e.g INT_MIN
), which contain the numerical values of the data types limits. We can use these macros to check if our defined variables exceed the maximum allowable value for a particular data type. For example an unsigned char
variable can not store a value bigger than UCHAR_MAX
(255
).
Example of different data types variables
In the source code below we can find different types of variables (fixed-point and floating-point), declared and defined in the same instruction. These are defined with the maximum and minimum value of each data type.
#include <stdio.h> #include <limits.h> #include <float.h> int main(void) { char cVar = SCHAR_MIN; unsigned char ucVar = UCHAR_MAX; signed char scVar = SCHAR_MAX; short sVar = SHRT_MIN; unsigned short usVar = USHRT_MAX; signed short ssVar = SHRT_MAX; int iVar = INT_MIN; unsigned int uiVar = UINT_MAX; signed int siVar = INT_MAX; long lVar = LONG_MIN; unsigned long ulVar = ULONG_MAX; signed long slVar = LONG_MAX; long long llVar = LLONG_MIN; unsigned long long ullVar = ULLONG_MAX; signed long long sllVar = LLONG_MAX; float fVar = FLT_MAX; double dVar = DBL_MAX; long double ldVar = LDBL_MAX; printf("SCHAR_MIN \t %d\n", cVar); printf("UCHAR_MAX \t %u\n", ucVar); printf("SCHAR_MAX \t %d\n", scVar); printf("SHRT_MIN \t %d\n", sVar); printf("USHRT_MAX \t %u\n", usVar); printf("SHRT_MAX \t %d\n", ssVar); printf("INT_MIN \t %d\n", iVar); printf("UINT_MAX \t %u\n", uiVar); printf("INT_MAX \t %d\n", siVar); printf("LONG_MIN \t %ld\n", lVar); printf("ULONG_MAX \t %lu\n", ulVar); printf("LONG_MAX \t %ld\n", slVar); printf("LLONG_MIN \t %lld\n", llVar); printf("ULLONG_MAX \t %llu\n", ullVar); printf("LLONG_MAX \t %lld\n", sllVar); printf("FLT_MAX \t %e\n", fVar); printf("DBL_MAX \t %le\n", dVar); printf("LDBL_MAX \t %Le\n", ldVar); return (0); }
Compiling and running the executable displays the following text:
SCHAR_MIN -128
UCHAR_MAX 255
SCHAR_MAX 127
SHRT_MIN -32768
USHRT_MAX 65535
SHRT_MAX 32767
INT_MIN -2147483648
UINT_MAX 4294967295
INT_MAX 2147483647
LONG_MIN -2147483648
ULONG_MAX 4294967295
LONG_MAX 2147483647
LLONG_MIN -9223372036854775808
ULLONG_MAX 18446744073709551615
LLONG_MAX 9223372036854775807
FLT_MAX 3.402823e+38
DBL_MAX 1.797693e+308
LDBL_MAX 1.797693e+308
One important observation is that, for the compiler used in this example, the double
and long double
data type have the same maximum value even if they are defined by different macros, DBL_MAX
and LDBL_MAX
respectively.
Integer overflow
What is happening if, by mistake, we exceed the limits contained in a certain data type. For example, we declare a variable as unsigned char
and assign the value of 255
. If we add 1
to this variable the result will be 256
which will be outside the range of unsigned char
.
Integer overflow occurs when the value of an integer type variable exceeds its maximum limits. To understand what’s happening let’s look at the following example:
#include <stdio.h> #include <limits.h> int main(void) { unsigned char ucVar1, ucVar2; signed char cVar3, cVar4; ucVar1 = UCHAR_MAX; ucVar2 = ucVar1 + 1; cVar3 = SCHAR_MIN; cVar4 = cVar3 - 1; printf("ucVar1 = %u\n", ucVar1); printf("ucVar2 = %u\n", ucVar2); printf("cVar3 = %d\n", cVar3); printf("cVar4 = %d\n", cVar4); return (0); }
In this example we declared four variables, two unsigned char
and two signed char
. The usage of the signed
keyword is optional, the same behaviour is obtained without it. The idea behind the example is to assign the maximum value of the data type to one variable and then add/subtract one unit for the second variable of the same data type.
Running the executable outputs the following results:
ucVar1 = 255
ucVar2 = 0
cVar3 = -128
cVar4 = 127
If we perform an arithmetic operation which produces a result larger than the maximum above for a N-bit integer, an integer overflow occurs, which reduces the result to modulo N-th power of 2
, keeping only the least significant bits of the result and effectively causing a wrap around (reset). This behaviour may cause security problems leading to unexpected results and arbitrary code execution.
For any questions or observations regarding this tutorial please use the comment form below.
Don’t forget to Like, Share and Subscribe!
Shiva
Nice post bro. I really like this post