You are on page 1of 40

Embedded C Coding Standard

Document Revision History

<<Unique ID>>
Identifier

Version # Date Contributor Reason for change(s)


0.1 28.Mar.2009 AliS Draft Version

Approvals

Approver Name Role Date Signature


<< Name >> dd/mm/yyyy

Proprietary Information
This Document Contains AEC Proprietary
Information, and shall not be disclosed or used
for the benefit of others without the written permission of
the President & CEO or his designee.
Table of Contents

Topic Page #

Introduction ………………………………………………………... 3

General Rules ……………………………………………………… 4


Comments …………………………………………………………. 16
Data Types & Variables …………………………………………... 18
Functions …………………………………………………………... 22
Expressions & Statements ………………………………………... 29

References ………………………………………………………….. 40

2
INTRODUCTION

Objective

This coding standard for Embedded C is developed with the objective to


have a positive effect on
• Quality through avoidance of defects/bugs/errors - especially hard to
detect ones
• Maintainability by promoting commonality and avoiding
misinterpretations
• Portability
• Readability/Clarity
• Productivity

Applicability

This coding standard applies to all new C code that is part of Embedded
Software developed by Products Development Section/R&D. Whenever
existing code is modified (if the major portion of the file is being updated),
then update the source code to abide with the conventions outlined in this
document. This will ensure that old code will be upgraded over time.

Classification of Rules

[M] Mandatory: These rules should not be deviated without the


permission of Project/Team Leader.
[A] Advisory: These rules are although optional, may not be deviated
unless there is a good reason.

3
1: GENERAL RULES

1.1. Braces

Rule #1.1 [M]


Braces must surround all blocks of code following the keywords if, else,
switch, while, do and for statements even if the block contains only a null
statement or a single statement.

Example:

s1 interlock = OFF;
s2 if (stop)
s3 flag = ON;
s4 interlock = ON;
s5 if (interlock)
s6 open_doors();
s7 else
s8 apply_breaks();
s9 sound_alarm();

Q: There appear to be a problem with line #s4 & line #s9. Is the programmer
forgotten to put braces by mistake? OR it is just incorrect indentation?

4
1.2. Parentheses

Rule #1.2 [M]


In C expressions, you can assume that *,/, and % come before + and -. Put
parentheses around everything else.

Example:

if (flags & FLAG != 0)


{
result = n << 4 + m;
}

Q: Is the below code is same as the above?

if ((flags & FLAG) != 0)


{
result = (n << 4) + m;
}

5
1.3. Static

Rule #1.3 [M]


The keyword ‘static’ shall be used to declare all the variables & functions
that do not need to be visible outside of the file in which they are declared.

Example:


/* Declaring Static Variables */
static u8 m_demand_counter = 0;
….
/* Declaring Static Functions */
static void stop_process (void);

…..
….

/* Defining Static Functions */

static void stop_process (void)


{

….
….
}

6
1.4. Volatile

Rule #1.4 [M]


The keyword ‘volatile’ shall be used
a) To declare global variables accessible by any ISR
b) To declare a pointer to a memory mapped I/O peripheral register set

Example:

int etx_rcvd = FALSE;

void main()
{
...
while (!ext_rcvd)
{
// Wait
}
...
}

interrupt void rx_isr (void)


{
...
if (ETX == rx_char)
{
etx_rcvd = TRUE;
}
...
}

Q: The above program is not working if “optimization” is turned on. Which part
of the code is being removed due to optimization and what is the solution do you
think?

7
1.5. Const

Rule #1.5 [M]


The keyword ‘const’ shall be used
a) To declare variables that should not be changed after initialization
b) To define call-by-reference function parameters that should not be
modified (eg: char const * param)

Example:

const double pi = 3.14159265358979323846;

u16 my_func (u8 const *s);

8
1.6 Magic Numbers

Rule #1.6 [M]


Magic Numbers shall not be used.

Example:
/* Don’t code like this */
case 0x01:

transmit_handler(0x10);
reset_machine();

if (timed_out)
{
transmit_handler(0x60);
}
else
{
transmit_handler(0x20);
}

break;

/* Code like this */


case RESET_MACHINE:

transmit_handler(BUSY);
reset_machine();

if (timed_out)
{
transmit_handler(TIMED_OUT);
}
else
{
transmit_handler(READY_RESET);
}

break;

9
1.7 Naming of Source/Header Files

Rule #1.7 [M]


All Source & Header File names shall consist of only ‘lower-case’ letters,
numbers, and underscores (not in the beginning). No spaces or special
characters shall appear within the file name.

Example:

Don’t name the files like this:

Application Process.c
Application Process.h
Maximum Demand.c
Maximum Demand.h

Name the files like this:

appln_process.c
appln_process.h
max_demand.c
max_demand.h

10
1.8 Guards for Header Files

Rule #1.8 [M]


Precaution shall be taken in order to protect the contents of header file
being included twice:

Example:

#ifndef __FILE1_H__
#define __FILE1_H__
/* the following lines will be excluded by the preprocessor if the file is included
more than once */
….
….

#endif //__FILE1_H__

11
1.9 Enumerator List Initialization

Rule #1.9 [M]


In an enumerator list only the first member can be explicitly initialized.
OR initialize all the members explicitly.

Example:

….
typedef enum { res_norma=29, res_not_finished, res_user_define = 30 }
Release_response_reason ;

….

Q: What is the value of res_not_finished?

12
1.10 Function-like Macros

Rule #1.10 [M]


Function-like macros shall not be used. Use in-line functions instead.

Example:

#define square(x) ((x) * (x))


s = square (i++);

Q: What is the value of s if the value of i = 2?

13
1.11. goto, break, continue, auto & register

Rule #1.11 [M]


The keywords ‘Goto’, ‘continue’, ‘break (except in switch)’, ‘auto’ &
‘register’ shall not be used.

14
1.12 Line Width

Rule #1.12 [A]


Limit the width of a line to 80 columns.

Example:

/* Don’t code like this */


ratio = (load * stress - safety_margin - fudge_factor) / (length * width * depth -
shrinkage);

/* Better Way*/
top = (load * stress - safety_margin - fudge_factor);
bottom = (length * width * depth - shrinkage);
ratio = top / bottom;

15
2: COMMENTS

2.1 Disabled Code

Rule #2.1 [M]


No disabled code shall remain in the released code.

Example:

….
u16 a = 12;
u16 b = 2;
….

/*a = 24; */
b = a//* divide by 4 */4;

Q: What is the value of b?

16
2.2 Nested Comments

Rule #2.2 [M]


Comments shall not be nested.

Example:


u16 a;
u16 size;

/* set local variables
a = 0;
/* set the variable size
to a known value */
size = 100;

while (a < size )


{
do_some_thing ();
a++;
}
….

Q: How many times the function “do_something’’ will be called?

17
3: Data Types & Variables

3.1 Fixed Width Data Types

Rule #3.1 [M]


Typedefs that use size and signedness shall be used in place of basic data
types.

Example:

typedef unsigned char u8;


typedef signed char s8;
typedef unsigned short int u16;
typedef signed short int s16;
typedef unsigned long int u32;
typedef signed long int s32;

18
3.2 Variable Naming

Rule #3.2 [M]


All variable names shall be limited to ‘lower case’ letters, numbers and
underscores (not in the beginning). (In contrast, macros shall be limited to
‘upper case’ letters, numbers and underscores).
Also:
All global variables shall start with g_. (eg: g_master_flag)
All module (when limited to a single file) scope variables shall start with
m_. (eg: m_ee_flag)
All variable names shall contain minimum three characters (Excepting
loop counters).

Example:

u8 g_first_run = 2;

static u8 m_demand_counter = 0;

s8 entry_index = -1;

….
//#define MAX_COUNT 100
const u8 max_count = 100;

19
3.3 Variable Initialization

Rule #3.3 [M]


All variables shall be initialized at the time of declaration.

Example:

char ret_val; // Variable not initialized.

case A: ret_val = 3;
break;

Case B: ret_val = 6;
break;

Case C: #ifdef M2
ret_val = 4;
#endif
break;

default: ret_val = 0;
break;
….

return ret_val;
……

Q: Assume M2 is not defined. What is the output for Case C?

20
3.4 Hiding Variables

Rule #3.4 [M]


Identifiers in an inner scope shall not use the same name as an identifier in
an outer scope.

Example:

/* Distance traveled by the car in miles */


float location;
/*..... */
void display_location(void)
{
/* Location of current cursor */
int location; /* *** Hides previous declaration *** */
….

location = location * some_thing;

Q: The problem is that we've now used the same word for two different things. Is
location being updated is a global or a local?

21
4: Functions

4.1 Naming & prototypes

Rule #4.1 [M]


Function names shall consist of only ‘lower case’ letters numbers and
underscores (not in the beginning). All functions shall have a complete
prototype.

Example:

u8 ee_read_byte (u16 address);



static void stop_process (void);

22
4.2 Function Length

Rule #4.2 [M]


Function length shall be limited to one printed page (50 to 80 lines)

23
4.3 Function Complexity

Rule #4.3 [M]


Limit the Cyclomatic Complexity of a function to 10.

24
4.4 Indentation Levels

Rule #4.4 [M]


Limit the indentation/nesting to 3 levels.

Example:
/* Do not code like this; stop at 3 levels & re-design/factor */
if (x == y)
{
if (m== n)
{
if ( p == q)
{
if ( r == s)
{
switch (r)
{
case 1:
do_something();
switch (q)
{
case l:
….

break;

…..
…..
…..

25
4.5 Single Exit

Rule #4.5 [M]


The keyword ‘return’ shall appear a maximum of once in the body of a
function.

Example:

/* Don’t code like this with more than one ‘return’ statement */

case A: …
return (3);
break;

Case B: ….
return (6);
break;

Case C: #ifdef M2

return (4);
#endif
break;

default: …
return (0);
break;
….

26
4.6 Avoid Function Calls in ISR

Rule #4.6 [A]


No functions shall be called inside an ISR.

27
4.7 Unavoidable Function Calls in ISR

Rule #4.6 [M]


If any function is called inside an ISR, then define the function in the same
file in which ISR appears and make the called function as ‘static’.

Example:

volatile unsigned char vguc=0;

#pragma inline=forced //Compiler Specific


static unsigned char ISRHelper(void)
{
return (5);
}

#pragma vector=… //Compiler Specific


__interrupt void ISR(void)
{
vguc=ISRHelper();
}

28
5: Expressions & Statements

5.1 Mixing Signed & Unsigned

Rule #5.1 [M]


Never mix signed and unsigned quantities with relational operators.

Example:

u16 var_1;
s16 var_2;

if (var_1 > var_2)


{
do_something();
}
else
{
do_nothing();
}

Q: What is the output for the below values?

var_1 = 10;
var_2 = -1;

29
5.2 Casting

Rule #5.2 [A]


Implicit casting not allowed when there is possible data loss (e.g.:
assigning a wider type to narrower type)

Example:

u16 g_var1;
u8 var_2;
…..
if (…)
{
var_2 =g_ var_1;
}

Q: Possible Data loss. Is it a mistake by the programmer? OR intentional?

30
5.3 Float Comparison

Rule #5.3 [M]


Never directly test floating point values using the relational operators
“==, !=, <=, >=”

Example:

f32 var_1;
f32 var_2;
f32 var_3;
…..

if ((var_1 + var_2) == var_3)


{
do_something();
}
else
{
do_nothing();
}

Q: What is the output for the below values?

var_1 = 9.64;
var_2 = 20.56;
var_3 = 30.2;

31
5.4 Comma Operator

Rule #5.4 [M]


Comma Operator shall not be used.

Example:

for (i=0,j=10; i<10, j >MAX_COUNT; i++,j--)


{
do_something ();
}

Q: Does the loop come out when ‘i’ becomes 10?

32
5.5 Bit-wise Operations on Signed Integers

Rule #5.5 [M]


No bit-wise operators shall be used to manipulate signed integer data.

Example:

s32 g_var = -10;;


g_var >> =2;

Q: Does the “sign” gets extended?

33
5.6 Array Index

Rule #5.6 [M]


No signed quantities shall be used as array index.

Example:

u16 g_array [255];


u16 temp;
s8 index;

index = 128;
temp = g_array[index]
….

Q: Is ‘temp’ being assigned with legal data?

34
5.7 If-Else

Rule #5.7 [M]


Assignments shall not be made within ‘if’ or ‘else’ or ‘else if’ expression.

Example:

u8 x;
u8 y;

if (x = y) //Is this a typing mistake?
{
do_some_thing();
}
else
{
do_another_thing();
}

Q: What is the output for the below values?

x = 2;
y = 0;

35
5.8 If-Else If

Rule #5.8 [M]


Any ‘if’ statement with an ‘else if’ clause shall end with an ‘else’ clause.

Example:

u8 x;
u8 y;

if (x = y)
{
do_some_thing();
}
else if (x == 2)
{
do_another_thing();
}
else
{
catch_error ();
}

36
5.9 Default in Switch

Rule #5.9 [M]


Always include a default case in every switch.

Example:

switch (g_var_1)
{
case READ:
read_process();
break;

case WRITE:
write_process();
break;

case EXECUTE:

exec_process();
break;

Q: What happens when g_var_1 is not (READ|WRITE|EXECUTE). How


the out-of-range values can be caught?

37
5.10 Break in Switch

Rule #5.10 [M]


Every case in a switch shall end either with a break
or the comment /* Fall Through */

Example:

switch (g_error)
{
case 1:

break;

case 2:

case 3:

break;

default:

catch_error();
break;
}

Q: There is no ‘break’ in case 2. Is it a mistake by the programmer? OR intentional?

38
5.11 ++ and --

Rule #5.11 [A]


The increment and decrement operators shall not be mixed with other
operators in an expression.

Example:
u8 b[4] = { 7, 21, 249, 100 };


x = b[i] + i++;

Q: What is the value of x, if i = 2?

39
REFERENCES

Rule# MISRA-C:2004 Rule# Netrino Coding Standard v1.02


1.1 14.8 2.3
1.2 12.1 2.4
1.3 8.11 2.8
1.4 -- 2.8
1.5 16.7 2.8
1.6 -- 9.4
1.7 -- 5.1
1.8 19.15 5.4
1.9 9.3 --
1.10 19.7 7.3
1.11 14.4 & 14.5 2.7
1.12 -- 2.2
2.1 2.4 3.1
2.2 2.3 3.1
3.1 6.3 6.2
3.2 -- 8.1
3.3 9.1 8.2
3.4 5.2 --
4.1 -- 7.1
4.2 -- 7.2
4.3 -- --
4.4 -- --
4.5 -- 7.2
4.6 -- --
4.7 -- --
5.1 -- 6.3
5.2 10.1, 10.2, 10.3 & 10.4 --
5.3 13.3 6.4
5.4 12.10 9.1
5.5 12.7 6.3
5.6 -- --
5.7 13.1 9.2
5.8 14.10 9.2
5.9 15.3 9.3
5.10 15.2 9.3
5.11 12.13 --

40

You might also like