Работали ли вы с Embedded C++?

«Работали ли вы с Embedded C++?» — вопрос из категории Other, который задают на 25% собеседований C/C++ Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Да, имею опыт разработки на Embedded C++ для микроконтроллеров. Это не отдельный язык, а стиль использования C++ в условиях жестких ограничений по памяти (RAM/ROM), вычислительной мощности и без поддержки полной стандартной библиотеки.

Ключевые особенности и ограничения:

  • Отказ от дорогих фич: Часто отключаются RTTI, исключения (-fno-exceptions) и динамическое выделение памяти (new/delete) из-за накладных расходов и непредсказуемости.
  • Ограниченное использование STL: Используются только контейнеры с фиксированным размером или собственные реализации. Шаблоны применяются для полиморфизма во время компиляции (CRTP).
  • Прямой доступ к железу: Работа с памятью-отображенными регистрами через volatile указатели, битовые поля, встроенный ассемблер.
  • Детерминизм и низкие задержки: Критичен размер стека, время отклика в прерываниях (ISR).

Пример кода для управления светодиодом на ARM Cortex-M (регистр GPIO):

#include <cstdint>

// Адрес регистра данных порта A (ODR) для STM32
constexpr uint32_t GPIOA_BASE = 0x40020000;
constexpr uint32_t GPIOA_ODR_OFFSET = 0x14;
volatile uint32_t* const GPIOA_ODR = reinterpret_cast<uint32_t*>(GPIOA_BASE + GPIOA_ODR_OFFSET);

// Бит для светодиода на линии 5
constexpr uint32_t LED_PIN = 5;

class LedController {
public:
    static void turn_on() {
        *GPIOA_ODR |= (1U << LED_PIN);  // Установка бита
    }
    static void turn_off() {
        *GPIOA_ODR &= ~(1U << LED_PIN); // Сброс бита
    }
    static void toggle() {
        *GPIOA_ODR ^= (1U << LED_PIN);  // Инверсия бита
    }
};

// Использование в коде
int main() {
    // ... конфигурация пина как выхода ...
    while (true) {
        LedController::toggle();
        delay_ms(500); // Простая функция задержки
    }
}

Работал с платформами ARM Cortex-M (STM32, NRF52), AVR и ESP32. Писал драйверы для UART, SPI, I2C, обработчики прерываний, реализовывал конечные автоматы и протоколы связи, уделяя особое внимание оптимизации по размеру кода и энергопотреблению.