Přeskočit na hlavní obsah

Coding Style

Každá firma má svůj vlastní coding style.
Můj coding style vychází ze standardů používaných v automobilovém průmyslu — vylepšených pro vývoj embedded systémů — protože je z mého pohledu nejčitelnější a nejlépe udržovatelný.
Níže je zdůvodnění každého pravidla a toho, jak přispívá k přehlednosti a dlouhodobé udržovatelnosti.


🔡 Proměnné​

Proměnné musí používat pojmenování lower camelCase.
Název proměnné musí obsahovat alespoň tři znaky.

❌ Nesprávně​

int x, y, z;
for(int i = 0; i < 10; i++) { ... }

✅ Správně​

int loopIndex;
float temperatureCelsius;
uint8_t sensorCount;

📘 Proč: Každá proměnná musí mít smysluplný název.
Krátké, záhadné názvy ničí čitelnost a ztěžují údržbu kódu.


⚠️ Externí proměnné​

Existence proměnných extern je přísně zakázána.
Pokud takovou proměnnou někdo najde, měl by být její tvůrce veřejně lynčován (obrazně 😉).

💡 Důvod:
Externí proměnné se téměř nedají vysledovat — nelze snadno zjistit, kdo je zapisuje nebo čte.
Data vždy zapouzdřete za gettery a settery.


🧱 Datové typy​

Názvy typů se řídí vzorem lowerCamelCase, ale musí končit na _t,
podle standardního pojmenování používaného v <stdint.h> (např. uint8_t, uint16_t atd.).

✅ Příklad​

typedef uint16_t temperature_t;
typedef float voltage_t;
typedef uint8_t humidity_t;

🧩 Důvod:
Okamžitě poznáte, zda identifikátor představuje typ, nebo proměnnou.


🚫 Vyhněte se obecným vestavěným typům​

Nepoužívejte přímo ve svém projektu holé uint8_t, uint16_t atd.
Místo toho definujte vlastní, sémanticky smysluplné typedefy.

✅ Tím zabráníte míchání nekompatibilních proměnných:
nemůžete omylem přiřadit temperature_t do humidity_t.

temperature_t temp = 25;
humidity_t humidity = 40;
temp = humidity; // ❌ Compilation error

Tím se vynucuje typová bezpečnost a zkracuje se doba ladění.


🧭 Názvy funkcí​

Názvy funkcí musí používat styl UpperCamelCase.
Každá funkce by měla obsahovat prefix modulu, který objasňuje, komu patří.

✅ Příklad​

rcc_InitSystemClock();
rcc_GetClockFrequency();
gpio_SetPinState(GPIOA, PIN_5, true);

📘 Proč:
Je okamžitě jasné, zda je identifikátor proměnná, funkce, nebo typ.
Prefix modulu umožňuje snadno najít funkci v hierarchii projektu.


⚙️ Direktivy preprocesoru​

Direktivy preprocesoru a makra musí používat UPPER_CASE_WITH_UNDERSCORES.

✅ Příklad​

#define MAX_SENSOR_COUNT 8
#define ENABLE_DEBUG_MODE 1

📘 Proč:
Velkými písmeny je okamžitě zřejmé, že jde o symbol času překladu, nikoli o proměnnou za běhu.


📄 Názvy souborů​

Názvy souborů používají styl UpperCamelCase.
Každý název souboru musí začínat názvem modulu, následovaným podtržítkem a popisem funkcionality.

✅ Příklad​

Rcc_Config.c
Gpio_Handler.c
Modbus_Transport.c

🧩 Kompletní struktura organizace souborů je popsána na samostatné wiki stránce:
File Organization


🗂️ Výčtové typy (enumy)​

Výčtové typy používají UpperCamelCase pro typ a UPPER_CASE pro enumerátory.

✅ Příklad​

typedef enum
{
STATE_IDLE,
STATE_RUNNING,
STATE_ERROR
} systemState_t;

📘 Proč:
Hodnoty psané velkými písmeny odlišují konstanty výčtu od proměnných, zatímco přípona _t jasně označuje typ.


🧮 Konstanty​

Konstanty definované v kódu (nikoli makra) musí používat názvy v UpperCamelCase.

✅ Příklad​

const uint32_t SystemTimeoutMs = 5000;
const float PiValue = 3.14159f;

💡 Kdykoli je to možné, preferujte const před #define — poskytuje kontrolu typů a řízení rozsahu platnosti.


🧰 Struktury a unie​

Názvy struktur používají UpperCamelCase,
zatímco jejich členy používají lowerCamelCase.

✅ Příklad​

typedef struct
{
uint8_t deviceId;
uint16_t firmwareVersion;
float batteryVoltage;
} DeviceInfo_t;

📘 Proč:
Konzistentní velikost písmen jasně odlišuje typ struktury od jejích polí.


🔣 Makra a inline funkce​

  • Makra (#define) → UPPER_CASE_WITH_UNDERSCORES
  • Inline pomocné funkce → UpperCamelCase (stejně jako běžné funkce)

✅ Příklad​

#define ENABLE_INTERRUPTS() __enable_irq()
#define DISABLE_INTERRUPTS() __disable_irq()

static inline void DelayMs(uint32_t ms) { ... }

💬 Komentáře a dokumentace​

Pro všechny veřejné funkce, typy a makra používejte komentáře ve stylu Doxygen.

✅ Příklad​

/**
* @brief Initializes system clocks.
* @param None
* @retval None
*/
void Rcc_InitSystemClock(void);

💡 Komentáře udržujte krátké, přesné a psané anglicky.
Popisujte, proč se něco dělá, ne co se dělá — to by mělo být zřejmé z kódu samotného.


🧾 Pravidla formátování​

PravidloPopis
Odsazení4 mezery, nikdy tabulátory
Složené závorkyStyl K&R ({ na stejném řádku)
Maximální délka řádku120 znaků
MezeryVždy mezera za čárkou a kolem operátorů
Prázdné řádkyPoužívejte k vizuálnímu oddělení logických částí
Include guardyFormát #ifndef MODULE_FILENAME_H
Pořadí includů<system> → "project" → "module"

✅ Příklad​

#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);
}
}

🧩 Jmenné prostory a prefixy​

Každý modul musí mít jedinečný prefix (např. rcc_, gpio_, adc_).
Tím se zajistí, že se názvy funkcí a typů v systému nebudou kolidovat.

📘 Pravidlo pro zapamatování:

  • Prefix = název modulu
  • CamelCase = funkce
  • _t = typ
  • lowerCamelCase = proměnná

Příklad konzistence:

rcc_Init()
rcc_Config_t
rccState_t
rcc_GetClock()

✅ Shrnutí​

PrvekStylPříklad
ProměnnálowerCamelCaseloopIndex, sensorCount
TyplowerCamelCase + _ttemperature_t, systemState_t
FunkceUpperCamelCaseRcc_InitSystemClock()
Makro / DefineUPPER_CASE_WITH_UNDERSCORESMAX_BUFFER_SIZE
KonstantaUpperCamelCasePiValue
Název strukturyUpperCamelCaseDeviceInfo_t
Člen strukturylowerCamelCasedeviceId
Hodnota enumuUPPER_CASESTATE_IDLE
Název souboruUpperCamelCase + podtržítkoGpio_Handler.c