Mengapa saya tidak bisa menggunakan pointer alih-alih array dengan PROGMEM?

11

Saya saat ini mengubah beberapa perpustakaan untuk menggunakan flash, bukan RAM untuk penyimpanan string sehingga saya tidak kehabisan SRAM pada proyek.

Beberapa string di perpustakaan dinyatakan dengan cara ini:

const char *testStringA = "ABC";

Ini berbeda dengan bagaimana saya biasanya melihat ini dilakukan:

const char testStringB[] = "DEF";

Namun, saya berpikir bahwa keduanya setara ketika dinyatakan const dan diinisialisasi dalam deklarasi. Keduanya bekerja dengan baik dalam kode.

Saya mencoba memindahkan ini ke flash:

const prog_char *testStringC PROGMEM = "GHI";

Saya kemudian menemukan bahwa ini tidak berhasil. Itu menghasilkan kue gobbled ketika dicetak.

Namun, mengikuti pola yang lebih umum:

const prog_char testStringD[] PROGMEM = "JKL";

bekerja dengan baik.

Saya bisa melihat di pembongkaran:

00000068 <testStringC>:
  68:   04 01                                               ..

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

Jadi jelas pointer dan hasil PROGMEM di string / array tidak diinisialisasi.

Kenapa ini?

Kode contoh:

#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
sumber

Jawaban:

6

Nah, pertanyaan ini telah dijawab dengan bijak dalam jawaban untuk pertanyaan Stack Overflow C: perbedaan antara char pointer dan array .

Pada dasarnya, apa yang Anda nyatakan sebagai PROGMEM dengan,

const prog_char testStringD[] PROGMEM = "JKL";

adalah array dan memori yang ditunjuknya, yaitu elemen-elemen array, keduanya dalam stack scope saat ini. Sedangkan dengan:

const prog_char* testStringC PROGMEM = "GHI";

Anda mendeklarasikan pointer PROGMEM ke string konstan yang dapat tetap berada di tempat lain dalam memori, tetapi tidak dinyatakan sebagai string PROGMEM.

Meskipun saya tidak mengujinya, tetapi Anda harus mencoba menyatakan:

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

untuk benar-benar mengalokasikan string yang runcing dalam ruang PROGMEM. Saya kira itu harus bekerja, menggunakan F()makro Arduino , yang menambahkan banyak kode boilerplate untuk benar-benar memiliki hasil yang sama dengan deklarasi array.

Seperti yang dikatakan dalam komentar, jika tidak dalam konteks global, PSTR()makro dapat digunakan sebagai pengganti F()makro.

Simpler lebih baik: gunakan deklarasi array, bukan pointer!

Jika jawaban lain , __flashkualifikasi adalah solusi ketiga ;-)

zmo
sumber
Saya setuju sepenuhnya pada "simpler is better" - array jauh lebih jelas. Saya selalu tertarik ketika sesuatu tidak segera terlihat.
Cybergibbons
F () mengembalikan FlashStringHelper yang pada dasarnya sama, tetapi menggunakan PSTR () berfungsi dengan baik (selama Anda membawa konstanta di dalam fungsi).
Cybergibbons
memang, saya benar-benar menyarankan PSTR()makro dulu tetapi berubah F()sebelum mengirimkan, karena konstanta Anda adalah global dalam Q Anda, jadi saya lebih suka tetap dengan yang harus bekerja di kedua konteks.
zmo
3

Apa baris ini:

const prog_char *testStringC PROGMEM = "GHI";

Yang dilakukan adalah menulis kode prolog untuk menyalin karakter dalam string ke SRAM, dan kemudian menginisialisasi pointer yang tersimpan dalam flash ke lokasi SRAM ini. Anda harus memuat pointer melalui cara normal, dan kemudian melakukan dereferensi pointer seperti biasa.

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

Garis ini:

const prog_char testStringD[] PROGMEM = "JKL";

menciptakan array karakter dalam flash, memungkinkan Anda untuk mengaksesnya seperti yang diharapkan.

Ignacio Vazquez-Abrams
sumber