Safe C Guidelines for Embedded Systems

by Sanjay Mishra

Here are some safe C guidelines that I have found useful over the years. I also use a specific form of organizing header files that I have detailed here.

Make your code obvious

"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." --Brian Kernighan

Enough said. This is probably the most important safe C guideline.

I like writing code so that it reads like English (or any other written language). This means writing long and descriptive variable and function names, making sure that the spacing between code blocks is such that they look like paragraphs. Each paragraph should capture a key concept. Topic for another article?


Use the form (constant == variable) in comparison expressions

C allows assignment to be done in comparison expression so

if(x = 5)

is a legal expression in C. Now, at least for me, I often mistype a single "=" instead of "==" while writing code. This used to be a source of errors in my code till I discovered the following technique (in "Deep C Secrets" book ).

Always write comparisons in the form

if(5 == x)

instead of

if(x == 5)

now if I make a mistake and write

if(5 = x)

the compiler declares an error and stops.

Modern C compilers may issue warning messages if they see a statement like

if(x =5)

but I picked up my habit before compilers became modern :-)


Use #ifdefs instead of commenting out source code

Sometimes you may not want to compile certain portions of source code but still leave it in the source file. It is much better to use #ifdefs to achieve this purpose than to simply comment out the code. The reason is that as you are playing with code, commenting and uncommenting code you may introduce errors.

Do not write integers with leading zeroes, do not use octal notation

C treats integers starting with a leading zero as an octal number. So if you want to write 32

int x = 32;  //is 32

int x = 032 ; //is 3 *8 +2 = 26

This is yet another safe C guideline that saves hours of looking at code and asking ourselves what is going on here.


Allocate memory statically

If you can allocate memory statically, and in many embedded systems you can, you have avoided a common source of errors - memory management. I always try to allocate memory statically where I can, and I have been able to sleep at night, while my code has kept functioning for years and years without crashing.

Do not use recursion

Stack space in most embedded systems is limited. Recursion takes up more stack space, also making sure recursion depth stays within acceptable limits requires extra attention. Why have one more thing that can go wrong? Avoid recursion.

Use an ANSI C compiler to produce source code, although you may use C++ to do static checks

C++ is strictly speaking NOT a superset of C.

char Usage

For numbers use typedefs that explicitly specify the size of the number

stdint.h which is available in C99 standard defines these types for integers. If your C compiler is not C99 compliant, you can easily create these entries yourself

For example

Specifier               Equivalent                 Sign Bits        Bytes

int8_t              signed char Signed                8                1

uint8_t             unsigned char Unsigned         8                1 

int16_t short     Signed                               16                2

uint16_t           unsigned short Unsigned        16               2 

int32_t int        Signed                                32               4

uint32_t           unsigned int Unsigned           32               4 

int64_t             long long Signed                  64               8

uint64_t           unsigned long long Unsigned   64               8


I have found similar definitions very useful for float and double types also.

typedef float    float32_t;

typedef double float64_t;

typedef long double float128_t;


If you are unsure about your compile you can always use the sizeof() operator to find the storage for example

int i;

i = sizeof(long double);


This is a safe C guideline that reduces the thought required while writing code.

Turn on maximum warnings in the compiler

Let compiler do the work, turn on maximum warnings and error messages. Make sure your code does not produce any warnings. For gcc you can do this using the C flag -Wall .

Turn warnings into errors

For gcc you can use# -Werror : Make all warnings into errors.CFLAGS += -Werror

I find this an indispensable safe C guideline. It prevents me from being lazy and ignoring warnings.

Initialize static variables

Always initialize variables to 0. Some embedded C run times may skip this step.

Use parenthesis in complex expressions

If you have a complex expression use parenthesis instead of just depending on C operator precedence rules. This makes the code much easier to read and there is no run time penalty.

Another safe C guideline that I have been happy with. \

Use bit operators only on unsigned types

Do not compare floating point valuesFloating point numbers are imprecise due to the way they are stored. Small errors resulting from this storage may cause your code to go awry

For example

float32_t x = 3.0;

float32_t y = 12.0;

float32_t result = y/x;

if(4.0 == result){

}

result may never equal 4.0 exactly.

If you need to use floating point comparisons use the library supplied for this purpose with your environment or write a small library that takes into account floating point number representation inaccuracies.

gcc has a warnings flag that will produce a warning if you use floating point number to test for equality

#-Wfloat-equal

#Warn if floating point values are used in equality comparisons.

this is automatically turned on by -Wall directive

Avoid using bitfields

While bitfields pack maximum information into a short space, they are compiler dependent and not portable So if you have the luxury of a small amount of extra memory, do not use bit fields.

A safe C guideline that I have been happy with. I will pack data into bitfields on itty, bitty processors but that is a last resort.

Use braces with if and else

C allows a single statement to be there after if and else without braces. In practice I have found that I make more errors when I use that facility. Now I always put braces after if and else statements.


Top of Safe C Guidelines


Need More Help? Have An Opinion?

Do you need more help to solve your problem? Would you like to ask the author a question about your specific problem? Do you have a great idea about this?

We will post an answer within 2 business days. If you need more immediate assistance or you would like to discuss your issue privately, please use our contact us form or call us at 1-888-215-8557. We love solving technical issues and there is no charge if we solve your problem over email or over a short phone call.

[ ? ]

Author Information (optional)

To receive credit as the author, enter your information below.

(first or full name)

(e.g., City, State, Country)

Submit Your Contribution

 submission guidelines.


(You can preview and edit on the next page)