Pourquoi ne puis-je pas utiliser de pointeurs au lieu de tableaux avec PROGMEM?

11

Je modifie actuellement certaines bibliothèques pour utiliser flash au lieu de RAM pour le stockage de chaînes afin de ne pas manquer de SRAM sur un projet.

Certaines chaînes de la bibliothèque sont déclarées de cette manière:

const char *testStringA = "ABC";

Ceci est différent de la façon dont je vois normalement cela:

const char testStringB[] = "DEF";

Cependant, je pense que ces deux sont équivalents lorsqu'ils sont déclarés const et initialisés dans la déclaration. Les deux fonctionnent bien dans le code.

J'ai essayé de les déplacer pour flasher:

const prog_char *testStringC PROGMEM = "GHI";

J'ai alors constaté que cela ne fonctionnait pas. Il produisait du charabia lors de l'impression.

Cependant, suivant le schéma le plus habituel de:

const prog_char testStringD[] PROGMEM = "JKL";

fonctionne bien.

Je peux voir dans le démontage:

00000068 <testStringC>:
  68:   04 01                                               ..

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

Il est donc clair que le pointeur et PROGMEM entraînent l'initialisation de la chaîne / du tableau.

Pourquoi est-ce?

Exemple de code:

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

}
Cybergibbons
la source

Réponses:

6

Eh bien, cette question a été sagement répondue dans une réponse à la question C de débordement de pile : différences entre le pointeur de caractère et le tableau .

Fondamentalement, avec quoi vous déclarez PROGMEM,

const prog_char testStringD[] PROGMEM = "JKL";

est à la fois le tableau et la mémoire vers laquelle il pointe, c'est-à-dire les éléments du tableau, tous deux dans la pile de portée du courant. Alors qu'avec:

const prog_char* testStringC PROGMEM = "GHI";

vous déclarez un pointeur PROGMEM sur une chaîne constante qui peut rester ailleurs en mémoire, mais non déclaré en tant que chaîne PROGMEM.

Bien que je n'aie pas testé cela, mais vous devriez essayer de déclarer:

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

pour allouer réellement la chaîne pointée dans l'espace PROGMEM. Je suppose que cela devrait fonctionner, en utilisant la F()macro Arduino , qui ajoute beaucoup de code standard pour avoir réellement le même résultat que la déclaration de tableau.

Comme indiqué dans les commentaires, sinon dans un contexte global, la PSTR()macro pourrait être utilisée à la place de la F()macro.

Plus simple, c'est mieux: utilisez la déclaration de tableau, pas celle du pointeur!

Cf cette autre réponse , le __flashqualificatif est une troisième solution ;-)

zmo
la source
Je suis totalement d accord sur le "plus simple est meilleur" - le tableau est beaucoup plus clair. Je m'intéresse toujours quand quelque chose n'est pas immédiatement évident.
Cybergibbons
F () renvoie FlashStringHelper qui est essentiellement le même, mais l'utilisation de PSTR () fonctionne très bien (tant que vous apportez les consts à l'intérieur d'une fonction).
Cybergibbons
en effet, j'ai suggéré d'abord la PSTR()macro mais je l'ai changé F()avant de le soumettre, car vos consts sont globales dans votre Q, j'ai donc préféré m'en tenir à celle qui devrait fonctionner dans les deux contextes.
zmo
3

Qu'est-ce que cette ligne:

const prog_char *testStringC PROGMEM = "GHI";

ne consiste à écrire du code de prologue pour copier les caractères de la chaîne dans SRAM, puis initialise le pointeur stocké en flash sur cet emplacement SRAM. Vous devez charger le pointeur par des moyens normaux, puis déréférencer le pointeur comme d'habitude.

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

Cette ligne:

const prog_char testStringD[] PROGMEM = "JKL";

crée le tableau de caractères en flash, vous permettant d'y accéder comme prévu.

Ignacio Vazquez-Abrams
la source