为什么不能在PROGMEM中使用指针而不是数组?


11

我目前正在更改某些库,以使用闪存而不是RAM进行字符串存储,这样我就不会在项目上用完SRAM。

库中的某些字符串以这种方式声明:

const char *testStringA = "ABC";

这与我通常看到的情况不同:

const char testStringB[] = "DEF";

但是,我认为这两个在声明为const并在声明中进行初始化时是等效的。两者都在代码中正常工作。

我试图将它们移动到闪存:

const prog_char *testStringC PROGMEM = "GHI";

然后我发现这行不通。打印时正在产生gobbledegook。

但是,遵循以下更常见的模式:

const prog_char testStringD[] PROGMEM = "JKL";

工作正常。

我可以在反汇编中看到:

00000068 <testStringC>:
  68:   04 01                                               ..

0000006a <_ZL11testStringD>:
  6a:   4a 4b 4c 00                                         JKL.

因此很明显,指针和PROGMEM导致字符串/数组未初始化。

为什么是这样?

示例代码:

#include <avr/pgmspace.h>

const int BUFFER_LEN = 20;

const char *testStringA = "ABC";
const char testStringB[] = "DEF";
const prog_char *testStringC PROGMEM = "GHI";
const prog_char testStringD[] PROGMEM = "JKL";

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

void loop()
{
    char buffer[BUFFER_LEN];

    Serial.println(testStringA);
    Serial.println(testStringB);

    strncpy_P(buffer, testStringC, BUFFER_LEN);
    Serial.println(buffer);

    strncpy_P(buffer, testStringD, BUFFER_LEN);
    Serial.println(buffer);

    delay(1000);

}

Answers:


6

嗯,这个问题已经在堆栈溢出问题C:char指针和array之间的区别的答案中得到了很好的回答

基本上,您要声明为PROGMEM,

const prog_char testStringD[] PROGMEM = "JKL";

在当前作用域堆栈中既是数组又是它指向的内存,即数组的元素。鉴于:

const prog_char* testStringC PROGMEM = "GHI";

您声明了指向常量字符串的PROGMEM指针,该常量字符串可能会保留在内存中的其他位置,但未声明为PROGMEM字符串。

尽管我没有对此进行测试,但是您应该尝试声明:

const prog_char* testStringC PROGMEM = F("GHI");

在PROGMEM空间中实际分配指向的字符串。我它应该使用Arduino的F()macro来工作,该添加了许多样板代码,实际上具有与数组声明相同的结果。

如评论中所述,如果不在全局范围内,则PSTR()可以使用F()宏代替宏。

越简单越好:使用数组声明,而不是指针!

cf 其他答案__flash限定词是第三个解决方案;-)


我完全同意“越简单越好”-数组要清晰得多。当某些事情不是立即显而易见时,我总是很感兴趣。
Cyber​​gibbons 2014年

F()返回基本相同的FlashStringHelper,但是使用PSTR()可以正常工作(只要将const放入函数中)。
Cyber​​gibbons 2014年

实际上,我实际上首先建议使用PSTR()宏,但F()在提交之前将其更改为宏,因为您的const是Q中的全局常量,因此我宁愿坚持在两种情况下都可以使用的const。
zmo 2014年

3

这行是什么:

const prog_char *testStringC PROGMEM = "GHI";

这样做是写序号代码将字符串中的字符复制到SRAM,然后将存储在闪存中的指针初始化到该SRAM位置。您必须通过常规方式加载指针,然后照常取消引用指针。

const char *str = pgm_read_word(&testStringC);
Serial.println(str);

这行:

const prog_char testStringD[] PROGMEM = "JKL";

在Flash中创建字符数组,使您可以按预期访问它。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.