Изменение размера массива struct / char (для уменьшения использования памяти) - PullRequest
0 голосов
/ 14 апреля 2019

Это мой первый проект на Arduino / C ++ / ESP32. Я написал довольно большую программу и получил почти все работоспособное - за исключением того, что в конце концов я понял, что устройство будет периодически выдыхать (память) и идти на перезагрузку. Перезагрузка происходит потому, что я настроил сторожевой таймер для этого.

Есть одна область, где я думаю, что есть шанс уменьшить использование памяти, но мой опыт работы с c ++ "еще не там", чтобы я мог написать это сам. Любые указатели (не каламбур), пожалуйста? Я был на этом со вчерашнего дня, и избавление от одной ошибки приводит только к появлению новой ошибки. Более того, я не хочу придумывать что-то хакерское или может сломаться позже Это должен быть быстрый ответ для опытных людей здесь.

Позвольте мне объяснить код, который я предпочитаю реорганизовать / оптимизировать.

Мне нужно хранить кучу записей, которые мне нужно будет прочитать / изменить позже. Я объявил структуру (, потому что это связанные поля ) во всем мире. Теперь проблема в том, что мне может понадобиться сохранить 1 запись, 2 записи или 5 записей, которые я узнаю позже, только когда прочитаю данные из EEPROM. И это должно быть доступно для всех функций, поэтому оно должно быть глобальным объявлением.

Подводя итог

Вопрос 1 - как установить «NumOfrecs» позже в программе, как только данные будут считаны из eeprom.

Вопрос 2 - Размер (sizeOfUsername) имени пользователя массива char также может изменяться в зависимости от длины имени пользователя, считываемого из eeprom. Иногда это может быть 5 символов, иногда это может быть 25. Я могу установить его максимум до 25 и решить эту проблему, но тогда я не буду тратить впустую память, если многие имена пользователей будут всего 4-5 символов? Итак, вкратце - непосредственно перед копированием данных в eeprom в массив символов «username» можно установить его размер равным оптимальному размеру, необходимому для хранения этих данных (то есть размер данных + 1 байт для нулевого завершения).

struct stUSRREC {
  char username[sizeOfUsername];
  bool online;
}; 

stUSRREC userRecords[NumOfrecs];

Я ознакомился с целым набором функций, таких как strcpy, memset, malloc и т. Д., Но теперь у меня закончилось время и мне нужно оставить учебную часть еще на один день.

Я могу попытаться сделать это немного по-другому, где я не использую структуру и вместо этого использую отдельные массивы символов (для каждого поля, например, имя пользователя). Но с другой стороны, мне придется изменить размеры массивов, когда я читаю данные из eeprom.

Я могу объяснить все, что я пробовал, но это сделает этот вопрос излишне длинным и, возможно, приведет к потере некоторой ясности. Очень ценю любую помощь.

Отвечая на вопросы и ответы в SO, я пробовал некоторые случайные вещи, и, по крайней мере, этот небольшой фрагмент кода, приведенный ниже, кажется, работает (с точки зрения хранения меньших / больших значений)

struct stUSRREC {
  char username[];        
  bool online;                   
}; 

stUSRREC userRecords[5];

Тогда манипулируй этим

strcpy(userRecords[0].username, "MYUSERNAME");
strcpy(userRecords[0].username, "test");
strcpy(userRecords[0].username, "MYVERYBIGUSERNAME");

Мне удалось написать / переписать разные длины (см. Выше), и я могу прочитать их все правильно. Изменение размера userRecords может быть другой игрой, но это может немного подождать

Одна вещь, которую я забыл упомянуть, это то, что мне нужно будет изменять размер / размер массива (с именем пользователя) ТОЛЬКО ОДИН РАЗ. В самом setup() я могу читать / загружать необходимые данные в эти массивы. Я не уверен, открывает ли это какую-либо другую возможность. Остальная часть структуры / массива, которой я должен манипулировать во время работы, это только логические значения и значения int. Это совсем не проблема, потому что для этого не нужно изменять размеры.

С другой стороны, я уверен, что я не единственный, кто столкнулся с такой ситуацией. Любые советы / подсказки / указатели могут помочь многим другим. Ограничения на маленьких устройствах, таких как ESP32, становятся более заметными, когда вы действительно начинаете загружать их кучей вещей. У меня все это работало со «Струнами» (заглавная буква S), но периодическая перезагрузка (процессорное голодание?) Требовала от меня избавления от Струн. Даже в противном случае я слышу, что использование Strings (на ESP, Arduino и gang) - плохая идея.

1 Ответ

3 голосов
/ 14 апреля 2019

Вы пометили этот вопрос как C ++, поэтому я спрошу:

Можете ли вы использовать vector и string во встроенном коде?

#include <string>
#include <vector>

struct stUSRREC {
  std::string username;
  bool online;
  stUSRREC(const char* name, bool isOnline) :
       username(name), 
       online(isOnline)
  {
  }
};

std::vector<stUSRREC> userRecords;

Использование string как тип имени пользователя означает, что вы выделяете столько символов, сколько нужно для хранения имени, вместо того, чтобы назначить максимальный размер sizeOfUsername.Использование vector позволяет динамически увеличивать набор записей.

Затем добавить новую запись:

stUSRREC record("bob", true);
userRecords.push_back(record);

И вам больше не понадобится NumOfrecs.Это покрыто userRecrods.size()

...