Skip to main content

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 a temperature_t to a humidity_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 _t suffix 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 const over #define wherever 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โ€‹

RuleDescription
Indentation4 spaces, never tabs
BracesK&R style ({ on the same line)
Max line length120 characters
SpacesAlways space after commas and around operators
Empty linesUse 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โ€‹

ElementStyleExample
VariablelowerCamelCaseloopIndex, sensorCount
TypelowerCamelCase + _ttemperature_t, systemState_t
FunctionUpperCamelCaseRcc_InitSystemClock()
Macro / DefineUPPER_CASE_WITH_UNDERSCORESMAX_BUFFER_SIZE
ConstantUpperCamelCasePiValue
Struct nameUpperCamelCaseDeviceInfo_t
Struct memberlowerCamelCasedeviceId
Enum valueUPPER_CASESTATE_IDLE
File nameUpperCamelCase + underscoreGpio_Handler.c