为什么 F() 宏(将字符串存储在 .text 中)无法编译?

Why doesn't F() macro (to store string in .text) compile?

documentation on PROGMEM 的底部,它显示了将字符串编译到程序 .text 段中的一种非常简单的方法:

The F() macro

When an instruction like:

Serial.print("Write something");

is used, the string to be printed is normally saved in RAM. If your sketch prints a lot of stuff on the Serial Monitor, you can easily fill the RAM. If you have free FLASH memory space, you can easily indicate that the string must be saved in FLASH using the syntax:

Serial.print(F("Write something that is stored in FLASH"));

然而,我只是运气不好才能编译它。

#include <avr/pgmspace.h>
static const struct {short cmd; const char *txt;} cmds[] = {
    {2, F("Hi")},
};

它抱怨

t.c:3:  error: initializer element is not constant
{2, F("hi")},
^
t.c:3: error: (near initialization for 'cmds[0].txt')
exit status 1
initializer element is not constant

没有 F 宏,它编译得很好。

    {2, "Hi"},

有没有人有使用它的经验?我有 10K 个字符串想加入程序 space。

F宏只能用于代码的可执行部分,不能用于变量定义。并且因为struct成员不能有PROGMEM属性,你必须分两步完成:在PROGMEM中声明每个文本字符串,然后在struct中使用PROGMEM地址。

结构数组也可以在 PROGMEM 中。

static const char cmd_0_txt[] PROGMEM = "Hello";
static const char cmd_1_txt[] PROGMEM = "World";

struct cmd_t {short cmd; const char *txt; }; // the struct type

// An array of structs in PROGMEM
static const cmd_t cmds[] PROGMEM = {
    {2, cmd_0_txt},
    {2, cmd_1_txt},
};

void setup()
{
  Serial.begin( 9600 );
  Serial.println( F("Test") );

  for (uint8_t i=0; i < sizeof(cmds)/sizeof(cmds[0]); i++) {

    // First, read the PROGMEM txt member (a pointer to the text)
    const char *ptr = (const char *) pgm_read_word( &cmds[i].txt );  // cast required

    // Next, read each text character from that PROGMEM location
    for (;;) {
      char c = pgm_read_byte( ptr++ );
      if (!c)
        break;
      Serial.print( c );
    }
    Serial.println();
  }
}

void loop()
{}