Perché non posso usare i puntatori invece dell'array con PROGMEM?


11

Attualmente sto cambiando alcune librerie per usare flash invece di RAM per l'archiviazione di stringhe in modo da non rimanere senza SRAM su un progetto.

Alcune stringhe nella libreria sono dichiarate in questo modo:

const char *testStringA = "ABC";

Questo è diverso da come normalmente vedo questo fatto:

const char testStringB[] = "DEF";

Tuttavia, penso che questi due siano equivalenti quando dichiarati const e inizializzati nella dichiarazione. Entrambi funzionano bene nel codice.

Ho provato a spostare questi per lampeggiare:

const prog_char *testStringC PROGMEM = "GHI";

Ho quindi scoperto che questo non ha funzionato. Stava producendo gobbledegook quando stampato.

Tuttavia, seguendo il modello più comune di:

const prog_char testStringD[] PROGMEM = "JKL";

funziona bene.

Riesco a vedere nello smontaggio:

00000068 <testStringC>:
  68:   04 01                                               ..

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

Quindi è chiaro che il puntatore e PROGMEM danno come risultato l'inizializzazione della stringa / matrice.

Perchè è questo?

Codice di esempio:

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

}

Risposte:


6

Bene, a questa domanda è stata saggiamente data una risposta alla domanda C di Stack Overflow : differenze tra puntatore a caratteri e array .

Fondamentalmente, quello che stai dichiarando PROGMEM con,

const prog_char testStringD[] PROGMEM = "JKL";

è sia l'array che la memoria a cui punta, ovvero gli elementi dell'array, entrambi nello stack dell'ambito corrente. Considerando che con:

const prog_char* testStringC PROGMEM = "GHI";

dichiarate un puntatore PROGMEM a una stringa costante che può rimanere altrove in memoria, ma non dichiarata come stringa PROGMEM.

Anche se non l' ho provato, ma dovresti provare a dichiarare:

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

per allocare effettivamente la stringa appuntita all'interno dello spazio PROGMEM. Mi immagino che si deve lavorare, utilizzando di Arduino F()macro , che aggiunge un sacco di codice boilerplate effettivamente avere lo stesso risultato come dichiarazione di matrice.

Come detto nei commenti, se non in un contesto globale, la PSTR()macro potrebbe essere utilizzata al posto della F()macro.

Più semplice è meglio: usa la dichiarazione dell'array, non quella del puntatore!

Cfr che l'altra risposta , il __flashqualificatore è una terza soluzione ;-)


Concordo pienamente sul "semplice è meglio" - l'array è molto più chiaro. Mi interesso sempre quando qualcosa non è immediatamente evidente.
Cybergibbons

F () restituisce FlashStringHelper che è essenzialmente lo stesso, ma l'uso di PSTR () funziona bene (purché porti i contro all'interno di una funzione).
Cybergibbons

in effetti, in realtà ho suggerito prima la PSTR()macro ma sono cambiata F()prima di inviarla, perché i tuoi cons sono quelli globali nella tua Q, quindi ho preferito attenermi a quello che dovrebbe funzionare in entrambi i contesti.
zmo

3

Cosa questa linea:

const prog_char *testStringC PROGMEM = "GHI";

fa è scrivere il codice del prologo per copiare i caratteri nella stringa su SRAM, quindi inizializza il puntatore memorizzato in flash in questa posizione SRAM. È necessario caricare il puntatore con mezzi normali e quindi dereferenziare il puntatore come al solito.

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

Questa linea:

const prog_char testStringD[] PROGMEM = "JKL";

crea una serie di caratteri in flash, permettendoti di accedervi come previsto.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.