Por que não posso usar ponteiros em vez de matriz com PROGMEM?


11

No momento, estou alterando algumas bibliotecas para usar flash em vez de RAM para armazenamento de string, para que eu não fique sem SRAM em um projeto.

Algumas seqüências de caracteres na biblioteca são declaradas desta maneira:

const char *testStringA = "ABC";

Isso é diferente de como eu normalmente vejo isso sendo feito:

const char testStringB[] = "DEF";

No entanto, acho que esses dois são equivalentes quando declarados const e inicializados na declaração. Ambos funcionam bem no código.

Tentei movê-los para piscar:

const prog_char *testStringC PROGMEM = "GHI";

Eu então descobri que isso não funcionou. Ele estava produzindo um gobbledegook quando impresso.

No entanto, seguindo o padrão mais usual de:

const prog_char testStringD[] PROGMEM = "JKL";

funciona bem.

Eu posso ver na desmontagem:

00000068 <testStringC>:
  68:   04 01                                               ..

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

Portanto, fica claro que o ponteiro e PROGMEM resultam na seqüência / matriz não sendo inicializada.

Por que é isso?

Código de exemplo:

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

}

Respostas:


6

Bem, esta pergunta foi sabiamente respondida em uma resposta à questão C do Stack Overflow : diferenças entre o ponteiro do char e o array .

Basicamente, o que você está declarando como PROGMEM,

const prog_char testStringD[] PROGMEM = "JKL";

é a matriz e a memória que ela aponta, ou seja, os elementos da matriz, ambos na pilha de escopo da corrente. Considerando que com:

const prog_char* testStringC PROGMEM = "GHI";

você declara um ponteiro PROGMEM para uma cadeia constante que pode permanecer em outro lugar na memória, mas não declarada como uma cadeia PROGMEM.

Embora eu não tenha testado isso, você deve tentar declarar:

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

para realmente alocar a string apontada no espaço PROGMEM. Eu acho que deveria estar funcionando, usando a F()macro do Arduino , que adiciona muito código clichê para realmente ter o mesmo resultado que a declaração da matriz.

Como dito nos comentários, se não em um contexto global, a PSTR()macro poderia ser usada em vez da F()macro.

Mais simples é melhor: use a declaração do array, não a do ponteiro!

Se essa outra resposta , o __flashqualificador é uma terceira solução ;-)


Eu concordo totalmente com o "mais simples é melhor" - a matriz é muito mais clara. Eu sempre fico interessado quando algo não é imediatamente óbvio.
precisa saber é o seguinte

F () retorna FlashStringHelper, que é basicamente o mesmo, mas o uso de PSTR () funciona bem (desde que você traga os consts dentro de uma função).
precisa saber é o seguinte

na verdade, sugeri primeiro a PSTR()macro, mas mudei para F()antes de enviar, porque seus consts são globais no seu Q, então eu preferi ficar com o que deveria funcionar nos dois contextos.
Zmo

3

O que esta linha:

const prog_char *testStringC PROGMEM = "GHI";

faz é escrever um código de prólogo para copiar os caracteres na sequência para SRAM e, em seguida, inicializa o ponteiro armazenado no flash para esse local da SRAM. Você deve carregar o ponteiro por meios normais e, em seguida, desreferenciar o ponteiro como de costume.

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

Está linha:

const prog_char testStringD[] PROGMEM = "JKL";

cria a matriz de caracteres em flash, permitindo o acesso conforme o esperado.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.