Почему я не могу использовать указатели вместо массива с PROGMEM?

В настоящее время я изменяю некоторые библиотеки, чтобы использовать flash вместо RAM для хранения строк, чтобы у меня не закончилось SRAM в проекте.

Некоторые строки в библиотеке объявляются следующим образом:

const char *testStringA = "ABC";

Это отличается от того, как я обычно вижу это:

const char testStringB[] = "DEF";

Однако, я думаю, что эти два эквивалентны, когда объявлены const и инициализированы в объявлении. Оба отлично работают в коде.

Я попытался переместить их во flash:

const prog_char *testStringC PROGMEM = "GHI";

Затем я обнаружил, что это не сработало. Он печатал gobbledegook.

Однако, следуя более обычной схеме:

const prog_char testStringD[] PROGMEM = "JKL";

отлично работает.

Я вижу в разборке:

00000068 <testStringC>:
  68:   04 01                                               ..

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

Итак, ясно, что указатель и PROGMEM приводят к тому, что строка /массив не инициализируется.

Почему это?

Пример кода:

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

}
10 голосов | спросил Cybergibbons 5 MarpmWed, 05 Mar 2014 15:52:44 +04002014-03-05T15:52:44+04:0003 2014, 15:52:44

2 ответа


5

Хорошо, этот вопрос был правильно принят в ответе на вопрос о переполнении стека C: различия между указателем char и массивом .

В принципе, что вы объявляете как PROGMEM с,

const prog_char testStringD[] PROGMEM = "JKL";

- это как массив, так и память, на которые он указывает, то есть элементы массива, как в стеке текущей области. Принимая во внимание, что:

const prog_char* testStringC PROGMEM = "GHI";

вы объявляете указатель PROGMEM на константную строку, которая может оставаться в другом месте в памяти, но не объявлена ​​как строка PROGMEM.

Хотя я сделал not тест, но вы должны попытаться объявить:

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

, чтобы фактически выделить заостренную строку в пространстве PROGMEM. I guess он должен работать, используя Arduino F() , который добавляет много кода шаблона, чтобы фактически иметь тот же результат, что и объявление массива.

Как сказано в комментариях, если не в глобальном контексте, макрос PSTR() может использоваться вместо макроса F().

Проще проще: используйте объявление массива, а не указатель один!

Cf этот другой ответ , квалификатор __flash - это третье решение; - )

ответил zmo 5 MarpmWed, 05 Mar 2014 17:10:11 +04002014-03-05T17:10:11+04:0005 2014, 17:10:11
3

Что эта строка:

const prog_char *testStringC PROGMEM = "GHI";

это написать код пролога, чтобы скопировать символы в строке в SRAM, а затем инициализировать указатель , хранящийся во флэш-памяти, в эту папку SRAM. Вы должны загрузить указатель с помощью обычных средств, а затем разыменовать указатель как обычно.

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

Эта строка:

const prog_char testStringD[] PROGMEM = "JKL";

создает массив символов во флэш-памяти, что позволяет вам получить к нему доступ, как ожидалось.

ответил Ignacio Vazquez-Abrams 5 MarpmWed, 05 Mar 2014 17:07:26 +04002014-03-05T17:07:26+04:0005 2014, 17:07:26

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132