О строках и назначениях
У меня есть этот код, который работает:
String ErrorMsg;
.......
if(!UploadPacketError)
{
ErrorMsg="OK";
}
else
{
ErrorMsg="NOK";
}
Строка создает динамически размещаемый массив, которого я хочу избежать. Я бы предпочел что-то вроде:
unsigned char ErrorMsg[5];
......
if(!UploadPacketError)
{
strcpy(ErroMsg,"OK",3); // +1 для нулевого завершения?
}
else
{
strcpy(ErroMsg,"NOK",4); // +1 для нулевого завершения?
}
т.е. есть ли способ динамически присвоить значение массиву символов фиксированного размера?
Ура! Томас
@EmbSysDev, 👍0
2 ответа
Почти.
Во-первых, это char
, а не unsigned char
:
char ErrorMsg[5];`
Во-вторых, вы не указываете размер с помощью strcpy
:
strcpy(ErrorMsg, "OK");
Существует вариант strcpy
, называемый strncpy
, который копирует не более n
символов:
strncpy(ErrorMsg, "OK", 5);
Это используется для предотвращения переполнения буфера. Но при работе с такими строковыми литералами это довольно бессмысленно.
Также рекомендуется подход с фиксированными символами, но для полноты картины существует возможность "отказаться от использования класса String", ЕСЛИ вы ТОЛЬКО используете фиксированные И предопределенные строки для создания динамически изменяемых сообщений:
bool first = true;
String A = F("My first ");
String B = F("My second ");
String C = F("answer");
if (first) serial.println(A+C);
else serial.println(B+C);
Подробнее о F-макросе читайте здесь.
Вывод:
- Большие блоки текста в файловую систему (например, SPIFFS, LittleFS, SD)
- динамические тексты в достаточно большие фиксированные массивы символов и
- короткие сообщения (состоящие из фиксированных частей) можно создавать с помощью макроса F
Присвоение строк A, B и C будет выделять кучу и копировать данные в нее, тратя впустую ОЗУ. Добавление строк объединит их в памяти и вернет результат, тратя больше оперативной памяти. Никогда не бывает веской причины (или даже хорошего способа) использовать String
., @Majenko
@Majenko: для людей со случайным любительским интересом к программированию эффективность и производительность вряд ли будут движущими факторами по сравнению с простотой и читабельностью кода. Для больших проектов важен каждый бит, но использование прямого доступа к порту или cstrings не улучшит воспринимаемую производительность простого проекта цифрового термометра с ЖК-дисплеем 4x20, и «программисту» может быть очень сложно настроить его, чем при использовании digitalWrite(), литералы, операторы и методы String. Иногда «сойти с рук ___» означает «да, я могу модифицировать это» вместо «не знаю, что это вообще значит»; пожалейте нубов., @dandavis
@dandavis Я сказал «уважительная» причина. Это *не* веская причина. Это причина, но не хорошая. Дело не в эффективности или производительности. Речь идет о том, что кто-то пишет какой-то, казалось бы, простой код, а затем через некоторое время появляется здесь и говорит: «Мой Arduino случайно падает через несколько часов, и я не могу понять, почему». И, конечно же, они использовали String. И куча раздробилась, и переполнилась., @Majenko
- strcmp, похоже, не работает
- Хранение значений широты и долготы в виде символов с заданной точностью
- Массив float в строку, разделенную запятыми
- Чтение из SPIFFS - Как лучше всего работать со строковым (или char) массивом с неопределенной длиной?
- Как преобразовать строку в шестнадцатеричный массив
- Как отсортировать строку с числом по возрастанию
- Прокрутка текста I2C
- Ничего не получено от функции, возвращающей массив строк
Спасибо Маженко. Есть ли способ сделать что-то вроде: String flashhtml = "<h1>Programming</h1><h2>" + ErrorMsg + "Programming Over"; Что-то похожее на объединение нескольких фиксированных строк и переменных строк? Я знаю, что есть и другие способы сделать это, но я искал самый простой вариант., @EmbSysDev
В буфер символов подходящего размера? Да.
strcpy
заменяет содержимое строки с самого начала.strcat
объединяет больше содержимого в конец.strcpy(buffer, "<h1>Программирование</h1><h2>"); strcat(буфер, ErrorMsg); strcat(buffer, "Программирование завершено"); ...
, @MajenkoПотрясающе, Маженко, именно то, что я искал!, @EmbSysDev
@EmbSysDev У меня есть небольшой пост в блоге о замене String строками C. https://majenko.co.uk/blog/evils-arduino-strings, @Majenko
Действительно очень хороший блог. Arduino — замечательный инструмент, но, похоже, он поможет вам напортачить по-крупному. Я думаю, как и все остальное, человек учится, сначала напортачив, @EmbSysDev
@majenko Извините за вопросы, но не буду strncpy(ErrorMsg, "OK", 5); написать терминатор за границы, не должен ли это быть strncpy(ErrorMsg, "OK", 4); для char[5] ? Как обычно я делаю это как strncpy(ErrorMsg, "OK", strlen (ErrorMsg)-1), чтобы быть в безопасности, @Codebreaker007
Нет. 5 включает терминатор, если он есть в первых 5 байтах. Но даже в этом случае он все равно будет обрабатывать только 3 байта, поскольку останавливается на NULL до того, как достигнет предела в 5., @Majenko
Да, ясно на примере «хорошо», но если я сделаю «сначала», это не выйдет за пределы границ, поскольку это может быть проблемой для общего использования strncpy Спасибо за ваше время, @Codebreaker007
Нет, вы просто не получите нулевой терминатор., @Majenko
http://www.cplusplus.com/reference/cstring/strncpy/, @Majenko