Time to take a look at data types. For now, we will be focusing on primitive data types. What separates primitive types from other types is that they cannot be reduced or deconstructed. If you are a chemistry person, you can think of them as atoms, the most basic building block of matter.
Example Program
#include <stdio.h>
int main()
{
char c = 'a';
unsigned char b = 240;
int i = -20;
unsigned int u = 12;
float f = 2.3;
double d = 10.2364;
printf("%c\n",c);
printf("%hhu\n",b);
printf("%d\n",i);
printf("%u\n",u);
printf("%f\n",f);
printf("%f\n",d);
return 0;
}
When compiled and run, you will see the following output:
a 240 -20 12 2.300000 10.236400
Bits and Bytes
The byte is the most basic unit of information that usually consists of eight bits. The most likely explanation for selecting 8 bits per byte is that 8 bits is the number of bytes used to encode a single character of ASCII text. Some data types are made up of more than one byte, and how each byte is used depends on what type of information is being stored. It’s not critical to understand exactly how binary numbers work, but if you would like to, this is a decent guide.
Signed and Unsigned
For unsigned data types, we do not want negative values, meaning that each bit is used to store a positive value. For signed data types, one bit is used to indicate whether the value is signed.
Characters
As previously mentioned, a single byte is the amount of memory needed to encode a single letter. In the C programming language, this is represented by the char type. It can be signed or unsigned.
char c = 'a';
unsigned char b = 240;
As our example program demonstrates, you can store either characters or numeric values in the char type. It is worth noting that the signed or unsigned qualifier will be ignored if you are storing characters instead of numeric values.
Integers
If you plan on using chars for numeric values, one of the downsides is that you only have one byte to work with. As a result, the range is limited to [0,255] for unsigned and [-128,127] for signed values. This makes int types better suited for numerical purposes. In most systems, an int is 4 bytes. This gives us a range of [0, 4,294,967,295] for unsigned int and [−2,147,483,647, 2,147,483,647] for signed int.
int i = -20;
unsigned int u = 12;
By default, all int types are signed unless otherwise specified. So if you want a signed int, you can just declare an int, as we have done in our example program.
Floating Point Numbers
Both char and int types are limited by their inability to store or calculate decimal values. C provides us with two different options for this. The first is float type, which is 32 bits, and the other is double, which is 64 bits.
float f = 2.3;
double d = 10.2364;
There is no universal standard for these types, but most modern systems use a standard defined by IEEE. There is one standard for float and one for double. Also note that both types are signed, no unsigned option is provided.
Long and Short
Short and long can provide additional size options for integer types, but I think there is a better way to accomplish this, which I will cover later. If you really want to learn about them, this reference is helpful.
Printing Different Types
At this point, you have seen the printf function and are familiar with using formatting specifiers. We have already covered using %d to print a signed integer, but there are other specifiers for printing other types, as demonstrated in our code:
printf("%c\n",c);
printf("%hhu\n",b);
printf("%d\n",i);
printf("%u\n",u);
printf("%f\n",f);
printf("%f\n",d);