One of the unique challenges of writing embedded software is that it requires the programmer to understand minute details of not only the hardware but also the programming language that they use to bring the hardware alive. Sometimes the simplest of concepts is far more complicated than someone might suspect. This is particularly true when it comes to understanding basic variable types within the C language.
Every programmer is familiar with the common variable types of char, integer, long, etc. Many programming languages include these variable types but they don’t necessarily represent the same physical memory space between languages. In fact, in the embedded world of C programming, the number of bytes that are used to store an integer will vary depending on the compiler and target platform! Any new developer might think that surely this cannot be the case but take a look at the experimental results taken from three different embedded microcontrollers in Figure 1.
Figure 1 – Using Sizeof() to get the number of bytes to store each data type
This has very real effects not only on how software interfaces to memory mapped devices but also can affect the performance of calculations and other functions within the software. It also makes it nearly impossible to port code from one platform to the next without the opportunity for bugs to breed like rabbits! This makes writing reusable code very difficult but thankfully starting with ISO C99 there is a solution to a developers portability woes.
The ISO C99 standard introduced portable data types through a header file named stdint.h. This header file is included with the compiler and creates data types of a fixed width. A fixed width data type ensures that an 8 bit variable is 8 bits, a 16 bit variable is 16 bits and so on and so forth. This ensures that C code using these data types is the same width from one platform to the next! An example of this can be seen in Figure 2 which shows some of the common signed and unsigned integer values.
Figure 2 – Common Integer Types
These are just a few examples of the types of variables that are defined in stdint.h. It is highly recommended that any developer spend some time examining this header. There are some very useful macros that can be used to get the minimum and maximum value that the datatype can store. This is great for initializing variables but also for boundary checking within code. There is even the definition of types such as int_fast8_t which is defined as the fastest 8-bit signed integer type. There is even definitions for types that are at least a certain width such as uint_least16_t.
If you are still using the built-in compiler variable types of char, int, long, etc, then this is a great time to examine stdint.h and start writing code that you can write once and port from here on out. Just remember that this header is built into C99 and if the compiler being used is not C99 or later it may be necessary to build your own version of stdint.h. It is definitely worth the exercise though in the long run!