C Coding Guideline

This document is prepared to help developers about how to write the code. It contains different types of code language rules. These rules make writing, maintaining, reviewing the code easier. Also some rules increase portability, …

Horizontal Spacing

Tab usage with space

In most projects, we are using number of spaces instead of using the tab character(\t). Most cases 4 spaces could be use for tab key. This can be set from settings of most IDE’s.

Unary Operators

The unary operators are written with no space between the operator and the operand.

!value 
~bits 
++i 
j-- 
(CPU_INT32U)x 
*ptr 
&x 
sizeof(x)

Binary Operators

The binary operators (and the ternary operator) are written with at least on space between the operator and operands.

c1 = c2; 
x + y 
i += 2; 
n > 0 ? n : -n 
a < b 
c >= 2

Expressions

Expressions within parentheses are written with no space after the opening parenthesis and no space before the closing parenthesis.

x = (a + b) * c;

if and if-else statements

if(x < y)
{
    return -1;
}
else if(x > y)
{
    return 1;
}
else
{
    return 0;
}

while, do-while and for loops

while(condition)
{
}

do
{
} while(condition);

for(int i = 0, j = argc; i < argc; i++, j--)
{
}

switch-case statements

switch(number)
{
case RED:
    return GREEN;
case GREEN:
    return BLUE;
case BLUE:
    return RED;
default:
    return BLACK;
}

Class definition

namespace examplenamespace {
    class ExampleClass {
        public:
            ExampleClass(int arg1, char arg2, char* arg3);
            ~ExampleClass();
            void public_func(char arg);
        private:
        	char class_member;
            void private_func(int arg);
    };
}

Naming Convention

In this section, there are some naming convention rules for C language.

These rules can be applied to:

  • Public and local functions
  • Typedef struct and enumeration
  • Public and local variables

Public and Local Functions

Naming convention of functions is important because if there is a good naming for functions, it would be easy to read the code.

Public Functions

Public functions can be called from another files. So it is better to put some prefix before function name:

Example:

void network_stackMgmt(int code);
bool uartIO_txEnable(void);

Local Functions

Local functions can be called only from inside the file that the function is written. So there is no need to put a prefix before function name:

static void clearBuffer(void);
static bool getState(int index);

Typedef Struct and Enumeration

Naming convention of typedef structures and enumerations is important because if there is a good naming, it would be easy to read the code.

Struct

If there is a good naming for the structure definition, it would be easy to read the code.

struct s_deviceManagerRing {
    uint8 link;
	char mac[18];
};

Typedef Struct

If there is a good naming for the typedef structure definition, it would be easy to read the code.

typedef struct {
    uint64_t mac;
    char ipServer[48];
    uint16_t portServer;
    uint16_t portClient;
} ts_gsmNet;

Enumeration

İf there is a good naming for the enumeration definition, it would be easy to read the code.

enum e_deviceManagerStates {
    E_DEVICE_MANAGER_INIT = 0,
	E_DEVICE_MANAGER_START,
	E_DEVICE_MANAGER_STOP,
};

Typedef Enumeration

If there is a good naming for the typedef enumeration definition, it would be easy to read the code.

typedef enum {
    E_DIO_E_INPUT_1 = 0,
} te_dioInputs;

Public and Local Variables

Naming convention of variables is important because if there is a good naming for variables, it would be easy to read the code.

Public Variables

Public variables can be used from another files. So it is important to have a prefix before the variable name like this:

char uartIO_respReady[6] = "READY";
char lon_respSet[6] = "SET\r\n";

Local Variables

Local variables can be used from only the file that they are written inside. So it is not important to have a prefix before the variable name.

static bool up;
static uint64_t local;
static uint8_t button;

File Content

It is better to have sections inside the file in every coding language. In this section there are some rules about file content.

File content should be separated with some comment blocks. So this way, it would be easy to find what we are looking for in the file content.

To get a documentation from the comments, Doxygen format is used for comments.

Doxygen Comment Blocks

This section is prepared to give some information about doxygen comment blocks and how to write them.

Function Documentation

Here is one example:

/**
* \brief Initializes the UART handle.
* \param config UART configuration string (ex. "COM1:115200,N,8,1")
* \return Returns a handle to the newly opened UART
*/
UART_HandleTypeDef *uartOpen(char *config)
{
    ...
}

Variable Documentation

Here is one example:

static uint8 mode[2]; /**< Uart mode * /

Define Documentation

Here is one example:

/* UART configuration */
#define UARTIO_EVEN     FALSE /**< Even parity */
#define UARTIO_PARITY   FALSE /**< Parity enabled */
#define UARTIO_WORDLEN  E_AHI_UART_WORD_LEN_8 /**< Word length */
#define UARTIO_ONESTOP  TRUE /**< One stop bit */

File Heading

A comment block must be placed at the beginning of each source code file (both code and header files) containing;

  • Filename
  • Brief(short description)
  • Details(detailed description)
  • Remarks(additional remarks)

Here is one example comment block:

/**
 * \file        Filename
 * \brief       A brief description, one sentence, one line.
 * \details     A detailed description of the file scope, it can span over
 *              multiple lines, can be omitted.
 * \remarks     Additional remarks.
 */

File Layout

Both source and header files must be divided by sections:

  • INCLUDE FILES
  • MACRO DEFINITIONS
  • LOCAL DATA TYPES
  • LOCAL CONSTANTS
  • VARIABLES
  • LOCAL FUNCTION PROTOTYPES
  • PUBLIC FUNCTION
  • LOCAL FUNCTION

Even if the section is empty, it’s comment block must be added to the file:

/*----------------------------< Section Name >--------------------------*/

Include Section

The INCLUDE FILES section should include all necessary header files.

/*------------------------------< Includes >-----------------------------*/
#include <iostream>
#include <thread>

Macro Definitions Section

The MACRO DEFINITIONS section should include all necessary macro defines.

/*--------------------------< Macro Definitions >-----------------------*/
#ifndef TRACE_APP
#define TRACE_APP	TRUE
#endif

Local Constants Section

The LOCAL CONSTANTS section should include all necessary constant variables.

/*--------------------------< Constants >-------------------------------*/
const uint32 msecCount = 1800;

Local Data Types Section

The LOCAL DATA TYPES section should include all necessary data type definitions.

/*----------------------------< Typedefs >-------------------------------*/
typedef struct
{
	bool	 rts;			/**< Current RTS setting */
	bool	 cts;			/**< Current CTS setting */
} 	ts_uart;

Local Variables Section

The LOCAL VARIABLES section should include all necessary local(static) variables.

/*---------------------------< Variables >------------------------------*/
static uint8 uart = APP_UART_0;

Local Function Prototypes Section

The LOCAL FUNCTION PROTOTYPES section should include all necessary local(static) function prototypes.

/*-------------------------< Prototypes >-----------------------------*/
static void delayMsec(uint32 period);

Public Function Section

The PUBLIC FUNCTION section should include all necessary public function declarations.

/*---------------------------< Public Function >------------------------*/
void dio_outputInitialise(void)
{
...
}

Local Functions Section

The LOCAL FUNCTION section should include all necessary local(static) function declarations.

/*-------------------------< Private Function >--------------------------*/
static void initialiseApp(void)
{
    ...
}

Abbreviations

Please refer to here to see abbreviations.