Coding Style
Every company has its own coding style.
My coding style originates from standards used in the automotive industry โ refined for embedded development โ because it is the most readable and maintainable style from my point of view.
Below is the reasoning behind each rule and how it contributes to clarity and long-term maintainability.
๐ก Variablesโ
Variables shall use lower camelCase naming.
The variable name must contain at least three characters.
โ Incorrectโ
int x, y, z;
for(int i = 0; i < 10; i++) { ... }
โ Correctโ
int loopIndex;
float temperatureCelsius;
uint8_t sensorCount;
๐ Why: Every variable must have a meaningful name.
Short, cryptic names destroy readability and make the code difficult to maintain.
โ ๏ธ External Variablesโ
The existence of extern variables shall be strictly prohibited.
If such variable is found, its creator shall be publicly lynched (figuratively ๐).
๐ก Reason:
External variables are nearly impossible to trace โ you canโt easily tell who writes or reads them.
Always encapsulate data behind getters and setters.
๐งฑ Data Typesโ
Type names follow the lowerCamelCase pattern but must end with _t,
following the standard naming used in <stdint.h> (e.g., uint8_t, uint16_t, etc.).
โ Exampleโ
typedef uint16_t temperature_t;
typedef float voltage_t;
typedef uint8_t humidity_t;
๐งฉ Reason:
You will immediately know if an identifier represents a type or a variable.
๐ซ Avoid Generic Built-In Typesโ
Do not use plain uint8_t, uint16_t, etc., directly in your project.
Instead, define custom, semantically meaningful typedefs.
โ This prevents mixing incompatible variables:
you canโt accidentally assign atemperature_tto ahumidity_t.
temperature_t temp = 25;
humidity_t humidity = 40;
temp = humidity; // โ Compilation error
This enforces type safety and reduces debugging time.
๐งญ Function Namesโ
Function names shall use UpperCamelCase style.
Each function should include the module prefix to clarify ownership.
โ Exampleโ
rcc_InitSystemClock();
rcc_GetClockFrequency();
gpio_SetPinState(GPIOA, PIN_5, true);
๐ Why:
It is immediately clear whether an identifier is a variable, function, or type.
The module prefix allows you to easily locate the function in the project hierarchy.
โ๏ธ Preprocessor Directivesโ
Preprocessor directives and macros must use UPPER_CASE_WITH_UNDERSCORES.
โ Exampleโ
#define MAX_SENSOR_COUNT 8
#define ENABLE_DEBUG_MODE 1
๐ Why:
Upper-case naming immediately tells you that it is a compile-time symbol, not a runtime variable.
๐ File Namesโ
File names use UpperCamelCase style.
Each file name must begin with the module name, followed by an underscore and the functionality description.
โ Exampleโ
Rcc_Config.c
Gpio_Handler.c
Modbus_Transport.c
๐งฉ The complete file organization structure is described in a separate wiki page:
File Organization
๐๏ธ Enumerationsโ
Enumeration types follow UpperCamelCase for the type and UPPER_CASE for enumerators.
โ Exampleโ
typedef enum
{
STATE_IDLE,
STATE_RUNNING,
STATE_ERROR
} systemState_t;
๐ Why:
Upper-case values distinguish enumeration constants from variables, while_tsuffix marks the type clearly.
๐งฎ Constantsโ
Constants defined in code (not macros) shall use UpperCamelCase names.
โ Exampleโ
const uint32_t SystemTimeoutMs = 5000;
const float PiValue = 3.14159f;
๐ก Prefer
constover#definewherever possible โ it provides type checking and scope control.
๐งฐ Structs and Unionsโ
Structure names use UpperCamelCase,
while their members use lowerCamelCase.
โ Exampleโ
typedef struct
{
uint8_t deviceId;
uint16_t firmwareVersion;
float batteryVoltage;
} DeviceInfo_t;
๐ Why:
Consistent casing clearly differentiates between the structure type and its fields.
๐ฃ Macros and Inline Functionsโ
- Macros (
#define) โ UPPER_CASE_WITH_UNDERSCORES - Inline helper functions โ UpperCamelCase (same as normal functions)
โ Exampleโ
#define ENABLE_INTERRUPTS() __enable_irq()
#define DISABLE_INTERRUPTS() __disable_irq()
static inline void DelayMs(uint32_t ms) { ... }
๐ฌ Comments and Documentationโ
Use Doxygen-style comments for all public functions, types, and macros.
โ Exampleโ
/**
* @brief Initializes system clocks.
* @param None
* @retval None
*/
void Rcc_InitSystemClock(void);
๐ก Keep comments short, precise, and written in English.
Describe why something is done, not what is done โ the code itself should make that clear.
๐งพ Formatting Rulesโ
| Rule | Description |
|---|---|
| Indentation | 4 spaces, never tabs |
| Braces | K&R style ({ on the same line) |
| Max line length | 120 characters |
| Spaces | Always space after commas and around operators |
| Empty lines | Use to visually separate logical sections |
| Include guards | #ifndef MODULE_FILENAME_H format |
| Includes order | <system> โ "project" โ "module" |
โ Exampleโ
#include <stdint.h>
#include "Rcc_Config.h"
#include "Gpio_Handler.h"
void Gpio_Init(void)
{
gpioState_t state = GPIO_LOW;
if (state == GPIO_LOW)
{
gpio_SetPinState(GPIOA, PIN_5, true);
}
}
๐งฉ Namespaces and Prefixingโ
Every module must have a unique prefix (e.g., rcc_, gpio_, adc_).
This ensures function and type names do not collide across the system.
๐ Rule of thumb:
- Prefix = module name
- CamelCase = function
- _t = type
- lowerCamelCase = variable
Example consistency:
rcc_Init()
rcc_Config_t
rccState_t
rcc_GetClock()
โ Summaryโ
| Element | Style | Example |
|---|---|---|
| Variable | lowerCamelCase | loopIndex, sensorCount |
| Type | lowerCamelCase + _t | temperature_t, systemState_t |
| Function | UpperCamelCase | Rcc_InitSystemClock() |
| Macro / Define | UPPER_CASE_WITH_UNDERSCORES | MAX_BUFFER_SIZE |
| Constant | UpperCamelCase | PiValue |
| Struct name | UpperCamelCase | DeviceInfo_t |
| Struct member | lowerCamelCase | deviceId |
| Enum value | UPPER_CASE | STATE_IDLE |
| File name | UpperCamelCase + underscore | Gpio_Handler.c |