Dlaczego nie mogę używać wskaźników zamiast tablicy w PROGMEM?


11

Obecnie zmieniam niektóre biblioteki, aby używały pamięci flash zamiast pamięci RAM do przechowywania ciągów, aby nie zabrakło SRAM w projekcie.

Niektóre ciągi w bibliotece są zadeklarowane w następujący sposób:

const char *testStringA = "ABC";

Różni się to od tego, jak zwykle to robię:

const char testStringB[] = "DEF";

Myślę jednak, że te dwa są równoważne, gdy zostaną zadeklarowane jako const i zainicjowane w deklaracji. Oba działają dobrze w kodzie.

Próbowałem przenieść je do flashowania:

const prog_char *testStringC PROGMEM = "GHI";

Potem odkryłem, że to nie działa. Po wydrukowaniu produkował gobbledegook.

Jednak zgodnie z bardziej typowym wzorem:

const prog_char testStringD[] PROGMEM = "JKL";

działa w porządku.

Widzę w demontażu:

00000068 <testStringC>:
  68:   04 01                                               ..

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

Jest więc jasne, że wskaźnik i PROGMEM powoduje, że łańcuch / tablica nie jest inicjowany.

Dlaczego to?

Przykładowy kod:

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

}

Odpowiedzi:


6

Cóż, na to pytanie mądrze odpowiedziano w odpowiedzi na pytanie C dotyczące przepełnienia stosu : różnice między wskaźnikiem char a tablicą .

Zasadniczo z czym deklarujesz się jako PROGMEM,

const prog_char testStringD[] PROGMEM = "JKL";

jest zarówno tablicą, jak i pamięcią, na którą wskazuje, to znaczy elementami tablicy, oba na stosie zakresu prądu. Natomiast z:

const prog_char* testStringC PROGMEM = "GHI";

deklarujesz wskaźnik PROGMEM do stałego ciągu, który może pozostać w innym miejscu w pamięci, ale nie zostanie zadeklarowany jako ciąg PROGMEM.

Chociaż tego nie testowałem, ale powinieneś spróbować zadeklarować:

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

aby faktycznie przydzielić wskazany ciąg w przestrzeni PROGMEM. Wydaje mi się, że powinno działać, używając F()makra Arduino , które dodaje dużo kodu typu „plateplate”, aby uzyskać taki sam wynik jak deklaracja tablicowa.

Jak powiedziano w komentarzach, jeśli nie w kontekście globalnym, PSTR()można użyć F()makra zamiast makra.

Prostsze jest lepsze: użyj deklaracji tablicowej, a nie wskaźnikowej!

Jeśli chodzi o inną odpowiedź , __flashkwalifikator to trzecie rozwiązanie ;-)


Całkowicie się zgadzam, że „prostsze jest lepsze” - tablica jest znacznie wyraźniejsza. Zawsze się interesuję, gdy coś nie jest od razu oczywiste.
— Cybergibbons,

F () zwraca FlashStringHelper, który jest zasadniczo taki sam, ale użycie PSTR () działa dobrze (o ile wprowadzasz consts do funkcji).
— Cybergibbons,

faktycznie, naprawdę zasugerowałem najpierw PSTR()makro, ale zmieniłem na F()przed przesłaniem, ponieważ twoje stałe są globalne w twoim Q, więc wolałem trzymać się tego, który powinien działać w obu kontekstach.
— zmo

3

Co ta linia:

const prog_char *testStringC PROGMEM = "GHI";

robi to napisać kod prologu, aby skopiować znaki z łańcucha do SRAM, a następnie inicjuje wskaźnik zapisany we flashu do tej lokalizacji SRAM. Musisz załadować wskaźnik w normalny sposób, a następnie wyrejestrować wskaźnik jak zwykle.

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

Ta linia:

const prog_char testStringD[] PROGMEM = "JKL";

tworzy tablicę znaków we flashu, umożliwiając dostęp do niej zgodnie z oczekiwaniami.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.