Путаница со строками и кучей

Надеюсь, у вас все хорошо.

Недавно после просмотра неизвестных сбоев я решил, что это может быть связано с тем, что я возился с «кучей»

После прочтения нескольких источников и понимания того, как это работает, это немного сбивает с толку. В некоторых источниках упоминается, что вы можете использовать F() все, и все будет в порядке, а в других упоминается резервирование места для строк с помощью «reserve()»

Мне нужны предложения, как устранить или контролировать?

Ниже я опубликую снимок кода, где несколько раз используется злобная строка.

////////отправка данных
    senddata(String(temp), String(hum), String(dis), String(flood), String(heaterstatus), String(humidifierstatus));
    //////////отправка данных

void senddata(String temp1, String hum1, String dis1, String flood1, String heater1, String humid1) {   /////отправка всех значений полей за один раз
  //////////отправка данных
  String getData = "GET /update?api_key=" + API + "&field1=" + temp1 + "&field2=" + hum1 + "&field3=" + dis1 + "&field4=" + flood1 + "&field5=" + heater1 + "&field6=" + humid1;
  sendCommand("AT+CIPMUX=1", 5, "OK");
  sendCommand("AT+CIPSTART=0,\"TCP\",\"" + HOST + "\"," + PORT, 15, "OK");
  sendCommand("AT+CIPSEND=0," + String(getData.length() + 4), 4, ">");
  esp8266.println(getData); delay(1500); countTrueCommand++;
  sendCommand("AT+CIPCLOSE=0", 5, "OK");
}

, 👍0


1 ответ


Лучший ответ:

0

Да, вы можете создать глобальную строку для getData, зарезервировать место и повторно использовать ее при каждом вызове функции. А что насчет String(getData.length())?

А параметры? Вы создаете новую строку для каждого параметра. А функция senddata не принимает ссылку на строку (String&), а создает новую копию каждого параметра String. Таким образом, при каждом вызове этой функции вы создаете 12 небольших строк. Это зло Стринга. Он делает все, чего бы это ни стоило.

И ваша команда sendCommand тоже принимает строку. Вот почему вы можете использовать "AT+CIPSTART=0,\"TCP\",\"" + HOST + "\"," + PORT и "AT+CIPSEND=0, " + String(getData.length() + 4) в качестве параметра. Таким образом, каждый вызов sendCommand создает две небольшие строки. Это 8. И каждый + в строке может вызвать перераспределение в куче.

Использовать строки C

void senddata(int temp1, int hum1, int dis1, int flood1, int heater1, int humid1) {
  char getData[256];
  snprintf(getData, sizeof(getData), "GET /update?api_key=%s&field1=%d&field2=%d&field3=%d&field4=%s&field5=%s&field6=%d",
      API, temp1, hum1, dis1, flood1, heater1, humid1);
  sendCommand("AT+CIPMUX=1", 5, "OK");
  char buff[32];
  snprintf(buff, sizeof(buff), "AT+CIPSTART=0,\"TCP\",\"%s\",%d" , HOST, PORT);
  sendCommand(buff, 15, "OK");
  snprintf(buff, sizeof(buff), "AT+CIPSEND=0,%d" , strlen(getData) + 4);
  sendCommand(buff, 4, ">");
}

void sendCommand(const char* command, const int timeout, const char* find) {
Макрос

F оптимизирует использование памяти, используя данные, хранящиеся во флэш-памяти. Функция snprintf_P — это версия snprintf для форматирования строки из флэш-памяти.

snprintf_P(getData, sizeof(getData), (const char*) F("GET /update?api_key=%s&field1=%d&field2=%d&field3=%d&field4=%s&field5=%s&field6=%d"),
  API, temp1, hum1, dis1, flood1, heater1, humid1);

Один из классов моей StreamLib — CStringBuilder. При этом код мог бы быть таким:

char getData[256];
CStringBuilder sb(getData, sizeof(getData));
sb.printf(F("GET /update?api_key=%s&field1=%d&field2=%d&field3=%d&field4=%s&field5=%s&field6=%d"),
    API, temp1, hum1, dis1, flood1, heater1, humid1);
sendCommand("AT+CIPMUX=1", 5, "OK");
char buff[32];
CStringBuilder sb2(buff, sizeof(buff));
sb2.printf(F("AT+CIPSTART=0,\"TCP\",\"%s\",%d") , HOST, PORT);
sendCommand(buff, 15, "OK");
sb2.reset();
sb2.print(F("AT+CIPSEND=0,"));
sb2.print(sb.length() + 4);
sendCommand(buff, 4, ">");
,

Привет @Juraj и спасибо за участие. Функция snprintf кажется очень интересной и подходящей. Я хорошо поискал хорошее руководство по этой функции, однако ответов было мало. Я хотел бы узнать, что означает использование %d и %s или чем они отличаются?, @Tad

printf 50 лет. http://www.cplusplus.com/reference/cstdio/printf/, @Juraj

Спасибо за это, это отличная ссылка. Знаете ли вы, есть ли какие-либо ограничения на то, где я могу его использовать? Кажется, никакие поплавки использовать нельзя? Есть ли какие-либо общие функции, которые могут конфликтовать?, @Tad

использование версий printf требует немного больше флэш-памяти. поддержку float можно включить, но это требует еще больше программной памяти. Альтернативой является использование моего класса CStringBuilder, который создает строку C, используя те же простые функции, что и Serial., @Juraj