1

I am trying to compile the following code:

logger.log_info(F(R"(some text here that may take
    multiple lines
    and here it is done.)"));

But the compiler exists with the following error:

error: unterminated raw string

I am able to use either R or F, but not both together. How should I be able to use them together?

5
  • Have you tried terminating the string manually, by adding \0 to the end? Maybe that helps, as the error message complains about the string not being terminated
    – chrisl
    Nov 9, 2020 at 17:56
  • @chrisl because I am using R, how should \0 be evaluated as string termination? Nov 9, 2020 at 18:00
  • @chrisl, I tried it, but I am not able to compile because the whole remaining file is now evaluated as part of the string. So this did not work. Nov 9, 2020 at 18:05
  • There were some bugs with raw string literals and the preprocessor in GCC a while back. What version are you using?
    – Mat
    Nov 9, 2020 at 18:26
  • @Mat, Arduino libraries 2.7.4; GCC: 7.3.0 Nov 9, 2020 at 18:52

1 Answer 1

5

If you put:

    #define DO_NOTHING(s) (s)

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

you can see g++ choke on preprocessing the raw string literal in the macro invocation with the latest esp8266 board package as of writing (version 2.7.4). This comes with g++ 4.8.2 for xtensa.

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

You may need to adjust the command-line for your system. donothing.h is just the macro and invocation described above.

Result:

# 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")

This does not happen with g++ 9.3.0 on an amd64 Linux target.

As a workaround you can reconstruct (more or less) what the F() macro does with the following:

    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);
    }
8
  • May I ask you why would you write something outside of the parenthesis of the literal? (namely xyz in your example)? If this is not gonna be shown anyway Nov 10, 2020 at 0:50
  • Do you have any suggestion to convert the output of the FPSTR(pgm_str) to std::string? because the is the type of the argument I am using. This is the error I get now: no known conversion for argument 1 from 'const __FlashStringHelper*' to 'const string& {aka const std::basic_string<char>&} Nov 10, 2020 at 0:55
  • 1
    std::string works by allocating from dynamic memory, except maybe for small strings, so in order to wind up with one you'd need to copy into it. In other words, at some point you'll have a second copy in RAM. What are you ultimately doing with the string? BTW: the arduino String class usually accepts const __FlashStringHelper *, but this inn't what your ultimately want and it would be a little nuts to load it into one and then the other.
    – timemage
    Nov 10, 2020 at 1:04
  • You are right, thanks for that point. That means, using const char * instead of String or std::string should be fine in this case, as no copying will happen and I will be fine to use this string for logging. Right? Nov 10, 2020 at 1:08
  • I'm not sure I understand. Where does logger.log_info come from? Is this a published library you can point me to? I ask, because if it was made with the Arduino in mind, it is likely that there is some support in it already for reading strings out of "PROGMEM".
    – timemage
    Nov 10, 2020 at 1:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.