Не удается скомпилировать макрос F() с помощью R "string"

Я пытаюсь скомпилировать следующий код:

logger.log_info(F(R"(некоторый текст здесь, который может занять
    несколько строк
    и вот это сделано.)"));

Но компилятор существует со следующей ошибкой:

ошибка: необработанная необработанная строка

Я могу использовать либо R, либо F, но не оба вместе. Как я должен иметь возможность использовать их вместе?

, 👍1

Обсуждение

Вы пробовали завершить строку вручную, добавив \0 в конец? Возможно, это помогает, так как сообщение об ошибке жалуется на то, что строка не завершается, @chrisl

@chrisl поскольку я использую R, как \0 должно оцениваться как завершение строки?, @Mohammed Noureldin

@chrisl, я пробовал, но я не могу скомпилировать, потому что весь оставшийся файл теперь оценивается как часть строки. Так что это не сработало., @Mohammed Noureldin

Некоторое время назад были некоторые ошибки с необработанными строковыми литералами и препроцессором в GCC. Какую версию вы используете?, @Mat

@Mat, библиотеки Arduino 2.7.4; GCC: 7.3.0, @Mohammed Noureldin


1 ответ


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

5

Если вы поставите:

    #define DO_NOTHING(s) (s)

    DO_NOTHING(R"xyz(Hello
    World)xyz")

вы можете видеть, что g ++ прерывает предварительную обработку необработанного строкового литерала при вызове макроса с последним пакетом платы esp8266 на момент написания (версия 2.7.4). Это поставляется с g ++ 4.8.2 для xtensa.

    ~/.arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/2.5.0-4-b40a506/bin/xtensa-lx106-elf-g++ -E  donothing.h

Возможно, вам потребуется настроить командную строку для вашей системы. ничего не делай.h - это просто макрос и вызов, описанные выше.

Результат:

# 1 "donothing.h"
# 1 "<command-line>"
# 1 "donothing.h"


donothing.h:3:13: warning: missing terminating " character [enabled by default]
 DO_NOTHING(R"xyz(Hello
             ^
(R"xyz(Hello World)
donothing.h:4:10: warning: missing terminating " character [enabled by default]
 World)xyz")
          ^
      xyz")

Этого не происходит с g ++ 9.3.0 на целевой платформе amd64 Linux.

В качестве обходного пути вы можете восстановить (более или менее) то, что макрос F() делает со следующим:

    void setup() {
      Serial.begin(9600);
    }

    void loop() {
      static const char pgm_str[] PROGMEM = (R"xyz(Hello
    World)xyz");

      Serial.println(FPSTR(pgm_str));
      delay(4000);
    }
,

Могу я спросить вас, зачем вам писать что-то за скобками литерала? (а именно *xyz* в вашем примере)? Если это все равно не будет показано, @Mohammed Noureldin

Есть ли у вас какие-либо предложения по преобразованию выходных данных FPSTR (pgm_str) в std::string? потому что это тип аргумента, который я использую. Это ошибка, которую я получаю сейчас: нет известного преобразования для аргумента 1 из 'const __FlashStringHelper *' в 'const string& {он же const std::basic_string<char>&}, @Mohammed Noureldin

std::string работает путем выделения из динамической памяти, за исключением, возможно, небольших строк, поэтому для того, чтобы получить одну из них, вам нужно будет скопировать в нее. Другими словами, в какой-то момент у вас будет вторая копия в оперативной памяти. Что вы в конечном счете делаете со строкой? КСТАТИ: класс arduino String обычно принимает const __FlashStringHelper * , но это не то, чего вы в конечном итоге хотите, и было бы немного глупо загружать его в один, а затем в другой., @timemage

Вы правы, спасибо за это замечание. Это означает, что использование const char * вместо String или std::string должно быть в порядке вещей в этом случае, так как никакого копирования не произойдет, и я буду в порядке, если использую эту строку для ведения журнала. Верно?, @Mohammed Noureldin

Я не уверен, что понимаю. Откуда берется logger.log_info? Это опубликованная библиотека, на которую вы можете мне указать? Я спрашиваю, потому что, если это было сделано с учетом Arduino, вполне вероятно, что в нем уже есть некоторая поддержка для чтения строк из "PROGMEM"., @timemage

Нет, на самом деле это не так, это написано когда-то мной, данные журнала - это просто некоторые строки, которые будут созданы во время выполнения. Например: logger.log_info("Текущее время" + time);. И аргумент, который он принимает, - std::string, я могу просто изменить его, конечно, на const char *. Однако теперь, после изменения типа аргумента, компилятор по-прежнему жалуется на тип: `ошибка: нет соответствующей функции для вызова 'Logger::log_info(const __FlashStringHelper *) const". Не могли бы вы продолжать пытаться помочь мне, пожалуйста, решить эту проблему? Я все равно приму ответ, потому что главный вопрос был решен!, @Mohammed Noureldin

Хех, к сожалению, это ужасная среда для того, чтобы пытаться поддерживать беседу. Вероятно, существует какая-то политика, запрещающая предлагать это, но вы можете найти меня на irc.freenode.net в #arduino я могу попытаться отредактировать ответ, чтобы включить процедуру загрузки std::string из __FlashStringHelper, если хотите. Или, я полагаю, это могло бы просто перейти в комментарий, поскольку это не является частью фактического ответа на вопрос., @timemage

Давайте [продолжим это обсуждение в chat](https://chat.stackexchange.com/rooms/116022/discussion-between-mohammed-noureldin-and-timemage)., @Mohammed Noureldin