Ошибка сегментации и огромная потребность в SRAM для Serial.println

Я написал свой собственный 'assert', так как хочу использовать его как для Windows, так и для Arduino. Класс вызывается из многих файлов (около 10).

AssertUtils.h:

#pragma once

#define assert(expr) AssertUtils::Assert2((expr), (__func__), (__FILE__), (__LINE__));

class AssertUtils
{
public:
    static void Assert2(bool expression, const char* funcName, const char* fileName, int line);
};

AssertUtils.cpp:

#include "AssertUtils.h"
#include "Arduino.h"

/* static */ void AssertUtils::Assert2(bool expression, const char* funcName, const char* fileName, int line)
{
    if (!expression)
    {
        Serial.println(funcName);
        Serial.println(fileName);
        Serial.println(line, DEC);
        Serial.flush();

        // Abort program execution.
        abort();
    }
}

Когда я компилирую это, использование SRAM составляет 1469 байт (вместе с остальной частью моего скетча и классов).

Когда я комментирую строку ниже, я получаю ошибку сегментации в случайном вызове assert (когда я комментирую этот вызов, я получаю его в следующем и т. д.).

    //Serial.println(funcName);

Когда я также комментирую второй оператор печати, компилятор сообщает об использовании только 1137 байт SRAM (чего я ожидаю, так как это было примерно равно до того, как я добавил класс Assert).

    //Serial.println(funcName);
    //Serial.println(fileName);

Вопросы:

  1. Как избавиться от ошибки сегментации?
  2. Как может быть, что около 332 байт используются для одного и двух дополнительных операторов печати? (возможно, это связано с буферизацией const char* (?)

, 👍0

Обсуждение

ошибка сегментации — это ошибка компилятора в версиях 1.6.22 и 1.6.23. подробнее здесь https://forum.arduino.cc/index.php?topic=619213.msg4195749#msg4195749, @Juraj

попробуйте F(__FILE__) и F(__func__). (измените тип параметра на __FlashStringHelper), @Juraj

@Juraj Каким-то образом это работает только для __FILE__, но не для __func__. В любом случае, используя F( __FILE__) была разница около -90B (вероятно, это полный путь, и он использовался только в одном файле)., @KIIV

поэтому компилятор оптимизирует параметры, если они не используются, @Juraj

Зачем вы тратите на это класс? Просто используйте отпечатки прямо в макросе., @Majenko

@juraj Спасибо (см. ответ, но не стесняйтесь добавлять свои собственные, если хотите, чтобы я проголосовал), @Michel Keijzers

@KIIV Спасибо (см. ответ, но не стесняйтесь добавлять свои собственные, если хотите, чтобы я проголосовал), @Michel Keijzers

@Majenko Спасибо (см. ответ, но не стесняйтесь добавлять свои собственные, если хотите, чтобы я проголосовал), @Michel Keijzers


1 ответ


Лучший ответ:

2

Обратите внимание, что это не МОЙ ответ, а приблизительное сочетание первых 5 комментариев из моего исходного вопроса.

Я сделал следующее:

  • (Юрай) Изменена версия компилятора на 6.21
  • (juraj) Добавлена буква F в F(__FILE__)
  • (KIIV) Удалено функция; это не сработало с помощью F flash helper, но я все равно могу однозначно найти код из-за имени файла и номера строки.
  • (Маженко) Я удалил класс и использую макрос. Это требует больше флэш-памяти (в зависимости от количества утверждений, которые я использую, но у меня все еще около 40% (было 35%).

Использование SRAM теперь составляет 1125 байт, даже меньше, чем я начинал.

Результирующий код показан ниже:

#define assert(expression) \
  if (!(expression)) \
  { \
    Serial.println(F(__FILE__)); \
    Serial.println(__LINE__, DEC); \
    Serial.flush(); \
    abort(); \
  }
,

О классе - в данном случае он использовался как старая форма пространств имен (поскольку пространства имен не существовали в С++ до 1990 года). Однако чаще использовалась структура, так как ей не нужен спецификатор public:., @KIIV