Преобразование массива символов в строку Flash
Я хотел бы передать форматированную строку в метод, который принимает __FlashStringHelper. Вот сигнатура метода:
void myMethod(const __FlashStringHelper *str);
Я использовал snprintf для форматирования строки:
char cmd[30];
snprintf(cmd, 30, "There are %d seconds in a minute", 60);
myMethod(F(&cmd[0]));
Очевидно, что вышесказанное не работает, но как я могу отформатировать флэш-строку?
ПРАВКА: Мне нужно включить целочисленную переменную в мою флэш - строку. В приведенном выше примере "60" - это переменная.
uint8_t nSeconds = 60;
char cmd[30];
snprintf(cmd, 30, "There are %d seconds in a minute", nSeconds);
myMethod(F(&cmd[0]));
@P. Avery, 👍0
Обсуждение1 ответ
Лучший ответ:
Прямой ответ
F()
берет неизменяемые строковые литералы, известные во время компиляции, и помещает их во flash ("PROGMEM") вместо оперативной памяти. функция snprintf()
создает строки во время выполнения и помещает их в изменяемый массив. Эти две вещи принципиально несовместимы.
Ограниченная конкатенация во время компиляции
Очень ограниченная форма того, что вы пытаетесь сделать, вероятно, может быть сделана следующим образом:
#define MY_STRINGIZE(x) #x
myMethod(F("There are " MY_STRINGIZE(60) " seconds in a minute"));
Это расширяется до:
myMethod(F("There are " "60" " seconds in a minute"));
Соседние строковые литералы объединяются вместе, что делает следующее:
myMethod(F("There are 60 seconds in a minute"));
Все это говорит о том, что вы могли бы просто написать там прямо 60. И здесь нет никаких возможностей форматирования snprintf.
В Arduino нет версии snprintf
для компиляции. И я не думаю, что функции языка C++ (или C) существуют для поддержки создания одного из них. Скорее всего, есть лучший способ достичь того, что вы действительно хотите сделать.
Работа над этим в целом
Часто нет необходимости связывать строки вообще, особенно если вы просто развернетесь и запишете их в поток
или , в более общем случае, напечатаете
подкласс , например , Serial
, LCD
, SDFile
, SoftwareSerial
и т. Д. Сцепление вещей для вас-это большая часть того, что они делают. Не обязательно делать это самому заранее.
Если у вас есть строковый литерал и константа (или переменная) и вы хотите сохранить как можно больше данных из оперативной памяти, использование двух отдельных .print()
/.println()
поможет вам сделать это:
printCapableThing.print(F("AT+CIPSTAT="));
printCapableThing.println(index);
F()
помещает"AT+CIPSTAT="
во flash.- Если индекс является константой, он также будет ветром, не будучи резидентом в RAM.
Боковое примечание
Я понимаю, что вы спрашиваете о том, чтобы получить как можно больше во flash, но я также не могу не указать, что эта же основная техника применяется к этой ужасной идее по несколько иным причинам:
Serial.println(String(F("Key ")) + keyname + " : " + value);
Это создает ужасающую путаницу распределений и освобождений и ненужного копирования, когда вы просто позволяете потоку/объекту печати выполнять свою работу, вызывая print()
/println()
несколько раз. Результирующий код более надежен, меньше и там, где не связан ввод/вывод, быстрее, когда вы это делаете.
Я думаю, что ему действительно нужна не компилируемая версия "snprintf" (это было бы совершенно бесполезно), а "myMethod", который принимает " const char*`., @PMF
Я абсолютно вижу использование для форматирования строки во время компиляции. Хотя да, вероятно, дело дойдет до последнего., @timemage
Я имею в виду, что вы могли бы написать реализацию для snprintf(cmd, 30, F("Есть %d секунд в минуту"), 60);
(не трудно сделать с временной копией). Но что-то вроде snprintf(F("..."), 30, F("Result is %d"), 60);
не может работать, потому что результат snprintf, конечно, не может быть во flash., @PMF
Мог бы, но не нужно. Уже существует вариант snprintf_P
, способный взять строку формата из PROGMEM. Вы, вероятно, использовали бы "PSTR" там вместо этого. Но я не вижу в этом смысла., @timemage
Спасибо всем за ответы! @timemage: "60 секунд в минуту" - это не мой точный случай использования, мой случай использования требует контекста, который я пытался опустить. В основном я пытаюсь понять, как можно отформатировать строку в памяти программы., @P. Avery
Я могу изменить ответ, если у вас есть добавить больше деталей к вашему вопросу. Но, если я воспринимаю вопрос довольно буквально, зная, что это пример, это то, что нет способа сделать это. Вы можете исходить *части* вашей в конечном счете скомпонованной строки *из* flash/progmem. Но *результат* формации должен будет оказаться в оперативной памяти. Часто нет необходимости конкатенировать строки вообще, особенно если вы просто развернетесь и запишете их в поток (например, Serial, LCD, SDFile и т. Д.)., @timemage
@timemage Как я могу использовать переменную внутри строки flash? Я добавил комментарии выше. Мне нужно подать AT-команду на GSM-щит. Команда требует индексной переменной. Я мог бы буквально написать множество методов для обработки этого, но ради понимания того, как это сделать, я предпочел бы написать один метод, который принимает в качестве входных данных целое число (индекс) и выдает следующую команду: AT+CIPSTAT={index}.
mySoftwareSerial->println(F("AT+CIPSTAT={index}"));
, @P. Avery
Я мог бы ответить на этот вопрос, но есть кое-что получше, о чем я упоминал выше. Вместо этого я исправлю ответ на то, что предложил бы там., @timemage
Отличный ответ, спасибо @timemage!, @P. Avery
- Как использовать SPI на Arduino?
- Библиотека DHT.h не импортируется
- Светодиоды: разница между общим анодом и общим катодом
- Как повторить кусок кода
- Почему эта программа на C++ не может прочитать Serial.write() моего arduino?
- Как изменить переменную при нажатии кнопки, подключенной к контакту 2
- Отображение двоичных данных на светодиодах
- Корпус кнопки и переключателя
Разве этот метод не имеет перегрузки, которая принимает " const char*`?, @Edgar Bonet