О строках и назначениях

У меня есть этот код, который работает:

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 для нулевого завершения?
    } 

т.е. есть ли способ динамически присвоить значение массиву символов фиксированного размера?

Ура! Томас

, 👍0


2 ответа


1

Почти.

Во-первых, это char, а не unsigned char:

char ErrorMsg[5];`

Во-вторых, вы не указываете размер с помощью strcpy:

strcpy(ErrorMsg, "OK");

Существует вариант strcpy, называемый strncpy, который копирует не более n символов:

strncpy(ErrorMsg, "OK", 5);

Это используется для предотвращения переполнения буфера. Но при работе с такими строковыми литералами это довольно бессмысленно.

,

Спасибо Маженко. Есть ли способ сделать что-то вроде: 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


0

Также рекомендуется подход с фиксированными символами, но для полноты картины существует возможность "отказаться от использования класса 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