¿Por qué no puedo usar punteros en lugar de matriz con PROGMEM?


11

Actualmente estoy cambiando algunas bibliotecas para usar flash en lugar de RAM para el almacenamiento de cadenas para que no me quede sin SRAM en un proyecto.

Algunas cadenas de la biblioteca se declaran de esta manera:

const char *testStringA = "ABC";

Esto es diferente a cómo normalmente veo esto hecho:

const char testStringB[] = "DEF";

Sin embargo, creo que estos dos son equivalentes cuando se declaran constantes e inicializados en la declaración. Ambos funcionan bien en código.

Intenté mover estos a flash:

const prog_char *testStringC PROGMEM = "GHI";

Entonces descubrí que esto no funcionaba. Producía gobbledegook cuando se imprimía.

Sin embargo, siguiendo el patrón más habitual de:

const prog_char testStringD[] PROGMEM = "JKL";

funciona bien.

Puedo ver en el desmontaje:

00000068 <testStringC>:
  68:   04 01                                               ..

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

Por lo tanto, queda claro el puntero y PROGMEM da como resultado que la cadena / matriz no se inicialice.

¿Por qué es esto?

Código de ejemplo:

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

}

Respuestas:


6

Bueno, esta pregunta se ha respondido sabiamente en una respuesta a la pregunta C de desbordamiento de pila : diferencias entre el puntero de caracteres y la matriz .

Básicamente, lo que estás declarando como PROGMEM con,

const prog_char testStringD[] PROGMEM = "JKL";

es tanto la matriz como la memoria a la que apunta, es decir, los elementos de la matriz, ambos en la pila de alcance actual. Mientras que con:

const prog_char* testStringC PROGMEM = "GHI";

declara un puntero PROGMEM a una cadena constante que puede permanecer en otra parte de la memoria, pero no se declara como una cadena PROGMEM.

Aunque Yo no prueba que, pero usted debe tratar de declarar:

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

para asignar realmente la cadena puntiaguda dentro del espacio PROGMEM. Yo supongo que debería estar trabajando, usando de Arduino F()macro , lo que añade una gran cantidad de código repetitivo para realmente tener el mismo resultado que la declaración de matriz.

Como se dijo en los comentarios, si no fuera en un contexto global, la PSTR()macro podría usarse en lugar de la F()macro.

Más simple es mejor: ¡use la declaración de matriz, no el puntero!

Si esa otra respuesta , el __flashcalificador es una tercera solución ;-)


Estoy totalmente de acuerdo con "lo más simple es mejor": la matriz es mucho más clara. Siempre me intereso cuando algo no es inmediatamente obvio.
Cybergibbons

F () devuelve FlashStringHelper, que es esencialmente el mismo, pero el uso de PSTR () funciona bien (siempre que traiga los consts dentro de una función).
Cybergibbons

de hecho, sugerí primero la PSTR()macro, pero cambié a F()antes de enviarla, porque tus consts son globales en tu Q, por lo que preferí seguir con la que debería funcionar en ambos contextos.
zmo

3

Qué es esta línea:

const prog_char *testStringC PROGMEM = "GHI";

lo que hace es escribir el código de prólogo para copiar los caracteres en la cadena a SRAM, y luego inicializa el puntero almacenado en flash en esta ubicación SRAM. Debe cargar el puntero por medios normales y luego desreferenciar el puntero como de costumbre.

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

Esta línea:

const prog_char testStringD[] PROGMEM = "JKL";

crea el conjunto de caracteres en flash, lo que le permite acceder a él como se esperaba.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.