Путаница со строками и кучей
Надеюсь, у вас все хорошо.
Недавно после просмотра неизвестных сбоев я решил, что это может быть связано с тем, что я возился с «кучей»
После прочтения нескольких источников и понимания того, как это работает, это немного сбивает с толку. В некоторых источниках упоминается, что вы можете использовать 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");
}
@Tad, 👍0
1 ответ
Лучший ответ:
Да, вы можете создать глобальную строку для 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, ">");
- avrdude ser_open() can't set com-state
- Float печатается только 2 десятичных знака после запятой
- ошибка: espcomm_upload_mem failed при загрузке скетча
- Печать массива байтов на экране последовательного монитора Arduino IDE
- Разные и самые быстрые способы вычисления синусов и косинусов в Arduino
- Arduino IDE Отказано В Разрешении На Загрузку, Ubuntu
- Нет заголовочных файлов (.h) в Documents\Arduino\libraries\arduino_144469 с демонстрационным кодом
- Связь Arduino master/slave с использованием RS485
Привет @Juraj и спасибо за участие. Функция snprintf кажется очень интересной и подходящей. Я хорошо поискал хорошее руководство по этой функции, однако ответов было мало. Я хотел бы узнать, что означает использование %d и %s или чем они отличаются?, @Tad
printf 50 лет. http://www.cplusplus.com/reference/cstdio/printf/, @Juraj
Спасибо за это, это отличная ссылка. Знаете ли вы, есть ли какие-либо ограничения на то, где я могу его использовать? Кажется, никакие поплавки использовать нельзя? Есть ли какие-либо общие функции, которые могут конфликтовать?, @Tad
использование версий printf требует немного больше флэш-памяти. поддержку float можно включить, но это требует еще больше программной памяти. Альтернативой является использование моего класса CStringBuilder, который создает строку C, используя те же простые функции, что и Serial., @Juraj