Инициализировать объект с константами PROGMEM
У меня есть класс со свойством const char *
:
class A
{
public:
const PROGMEM char* text;
};
void setup()
{
// A a{"Hello World!"};
// A a{PSTR("Hello World!")};
A a;
a.text = PSTR("Hello World!");
Serial.begin(9600);
delay(30);
Serial.println(a.text);
}
void loop()
{
}
Я хотел бы сэкономить немного оперативной памяти, используя PROGMEM
.
Как тогда инициализировать объект a
?
Очевидно, что так быть не может:
A a{PSTR("Hello World!")};
Это будет сделано:
A a;
a.text = PSTR("Hello World!");
Однако мне нужно передать строку конструктору.
@zhekaus, 👍0
Обсуждение2 ответа
Лучший ответ:
Жаль, что gcc поддерживает квалификатор __flash
только в режиме C,
не в C++, поэтому вместо этого мы должны использовать PROGMEM
. В отличие от __flash
, который
определяет переменную точно так же, как const
, атрибут PROGMEM
имеет только
эффект при выделении места для переменной. После того, как распределение выполнено,
компилятор забывает об атрибуте. В частности, заявление
например
const PROGMEM char* text;
не выделяет флэш-память, поэтому генерирует предупреждение
warning: ‘__progmem__’ attribute ignored [-Wattributes]
const PROGMEM char* text;
^
Таким образом, вы можете забыть об атрибуте при объявлении указателя, так как
нет такой вещи, как «указатель на PROGMEM
». Вы просто используете const char *
вместо этого.
Теперь вторая проблема заключается в том, что Serial.println()
что касается указателя выше, это обычный const char *
, поэтому он будет
интерпретировать его как адрес в оперативной памяти и печатать мусор. Если ты хочешь
Serial.println()
, чтобы знать, что вы даете ему адрес во флэш-памяти, вы
должен предоставить ему указатель const __FlashStringHelper*
.
Вот решение, которое я предлагаю. Протестировано на Uno-совместимой плате:
class A
{
public:
A(const char* s)
: text(reinterpret_cast<const __FlashStringHelper *>(s)) {}
const __FlashStringHelper* text;
};
void setup()
{
A a{PSTR("Hello World!")};
Serial.begin(9600);
Serial.println(a.text);
}
void loop(){}
Обновление: увидев последнюю версию ответа Юрая, я должен сказать
что я с ним согласен. Так как мы используем API Arduino, это делает больше
смысла для конструктора принимать const __FlashStringHelper*
и
чтобы вызывающая сторона использовала макрос F()
.
ваше решение работает отлично! большое спасибо!, @zhekaus
const char* text;
— это указатель на константу, а не указатель на константу (char * const text
— это указатель на константу). Таким образом, вы можете назначить указатель на постоянный массив символов в const char* text;
даже указатель на массив в PROGMEM.
Компилятор не знает разницы между указателем PROGMEM и указателем в SRAM. Вы должны правильно работать в коде с указателем на PROGMEM.
поэтому удалите PROGMEM из const PROGMEM char* text;
добавить конструктор для инициализации объекта.
A(const char* _text) {
text = _text;
}
а затем
A a(PSTR("Hello World!"));
ИЗМЕНИТЬ:
вы можете использовать макрос F() Arduino и тип __FlashStringHelper, потому что он поддерживается Serial print и другими.
class A
{
public:
A(const __FlashStringHelper* _text) {
text = _text;
}
const __FlashStringHelper* text;
};
void setup()
{
A a(F("Hello World!"));
Serial.begin(9600);
delay(30);
Serial.println(a.text);
}
void loop()
{
}
Тип __FlashStringHelper позволяет отличить строки PROGMEM от массивов символов в SRAM..
Это не ответ на мой вопрос. Как хранить строки во флэш-памяти? Строки должны быть переданы конструктору., @zhekaus
непонятно, чего вы не знаете. я расширил ответ, @Juraj
Гм... Ваше решение не позволит использовать Serial.println. И добавление пользовательского конструктора тут ни при чем., @zhekaus
@zhekaus, да, твой вопрос объединил 3 проблемы. Эдгар получил их все, но верное решение состоит в том, чтобы использовать макрос F, а не PSTR, если это возможно. я расширил ответ, @Juraj
- Записать во флэш-память с помощью PROGMEM
- Преимущества глобальных переменных перед статическими членами класса?
- Ошибка компиляции ESP8266: "previous declaration of 'HTTPMethod HTTP_HEAD'"
- Вспомогательный объект Flash String в качестве переменной
- Arduino IDE: как получить длину PROGMEM const?
- Использование программной памяти в ESP8266 по сравнению с AVR, а также как обрабатывать большие динамические строки
- Проблема с памятью Arduino со старыми чипами дисплея HP HDSP-2000
- Как использовать PROGMEM в файле .h/.cpp вместо файла .ino?
a.text = F("Hello World!");
делает то, что вы хотите?, @dandavis@dandavis, это не так. вы упустили, что a.text не является
const __FlashStringHelper*
, аconst char*
, @zhekaus