Skip to content
BoKSA

Namespaces and Code Organization

Namespaces and Code Organization

Introduction

As firmware grows, names collide: init(), Status, Timer in every module. C used prefixes: hal_spi_init, drv_motor_start. C++ adds namespaces — group related names without verbose prefixes. You also organize headers (.hpp) and link with C drivers via extern "C".

Good structure keeps application code readable and stops HAL symbols from clashing with your robot Control class.


Namespaces — folders for names

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
namespace drivers {

void uart_init(int baud);
class Motor { /* ... */ };

}  // namespace drivers

namespace app {

void run();

}  // namespace app

Use qualified names:

1
2
drivers::uart_init(115200);
drivers::Motor left_wheel(1);

In plain terms

A namespace is a surname for your functions. Motor alone might be ambiguous; drivers::Motor tells everyone which family you mean.

using — import with care

1
2
3
4
using drivers::Motor;
Motor m(1);  /* OK in .cpp */

using namespace drivers;  /* avoid in headers */

Never using namespace std; in a header — it pollutes every file that includes you. In .cpp files, limited using for locals is fine.


Namespace + class together

Tool Best for
Namespace Free functions, constants, enums
Class State + behaviour (object)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
namespace protocol {

constexpr uint8_t SYNC_BYTE = 0xAA;

uint16_t crc16(const uint8_t *data, size_t len);

class Frame {
public:
    bool parse(const uint8_t *buf, size_t len);
};

}  // namespace protocol

Headers in C++

Convention:

Extension Typical use
.h C headers, shared with C
.hpp / .hh C++ headers

Include guards (same as C):

1
2
3
4
5
6
7
8
#ifndef DRIVERS_MOTOR_HPP
#define DRIVERS_MOTOR_HPP

namespace drivers {
class Motor { /* ... */ };
}

#endif

Or #pragma once (widely supported). One header per class or small module group — not one giant everything.hpp.


Linking C and C++

Most HAL is C. C++ name mangling would break the linker if you mixed blindly. Wrap C headers:

1
2
3
4
5
6
7
8
9
#ifdef __cplusplus
extern "C" {
#endif

#include "stm32f4xx_hal.h"

#ifdef __cplusplus
}
#endif

extern "C" tells C++ compiler: use C linkage — symbol names match what hal_gpio.c exported.

Your main.cpp calls HAL_Init() without mangling errors.


Anonymous namespace — internal linkage

1
2
3
4
5
namespace {
    int helper_count = 0;

    void tick() { helper_count++; }
}

Symbols visible only in this translation unit — like static functions in C. Use for file-local helpers in .cpp files.


Project layout example

1
2
3
4
5
6
7
8
9
firmware/
  app/
    main.cpp
    robot.hpp / robot.cpp
  drivers/
    motor.hpp / motor.cpp
    uart.hpp / uart.cpp
  hal/          /* C */
    hal_gpio.c / hal_gpio.h

Dependency direction: appdrivershal. C++ application never includes vendor register headers directly if you can avoid it — keeps encapsulation real.


std namespace

Standard library lives in std:

1
2
3
4
5
#include <cstdint>
#include <array>

std::uint32_t ms;
std::array<uint8_t, 64> buffer;

On embedded, many std facilities are absent or trimmed (<iostream>, full <vector>). See Embedded C++ subset. <cstdint>, <array>, <algorithm> on headers-only parts are common on capable MCUs.


Relevant topics


Starting points

  1. Wrap one vendor hal_*.h with extern "C" in a C++ main.cpp.
  2. Move one module into namespace project_name { } — fix qualifiers.
  3. Draw include graph: which headers pull in HAL vs drivers only.
  4. Remove using namespace std from any header in a sample repo.

Focus points

  • Headers expose, sources implement — minimize #include in headers (forward declare when possible).
  • extern "C" at every C boundary.
  • No using namespace in headers — prevents surprise name clashes.
  • Consistent namingdrivers::, app::, or prefix style — pick one per repo.

Key points

  • Namespaces group names and reduce prefix noise.
  • extern "C" links C++ code with C HAL and libraries.
  • Header organization and include guards keep builds fast and dependencies clear.
  • Anonymous namespace hides file-local helpers — prefer over global static in C++.