Ошибка при передаче `time_t` и `struct tm`, ESP32

Мне нужно создать преобразователь времени эпохи, хранящегося в переменной time_t, в переменную struct tm, чтобы проверять/создавать определенную задачу каждый час или день. Эта функция также должна получить прошлое time_t для других целей.

Функция преобразования внутри библиотеки работает нормально (последние две строки предназначены для проверки, то есть преобразование было выполнено, как ожидалось):

void myIOT32::convEpoch(time_t in_time, struct tm *convTime)
{
  convTime = gmtime(&in_time);
  char time_char[40];
  sprintf(time_char, "%04d-%02d-%02d %02d:%02d:%02d", convTime->tm_year + 1900, convTime->tm_mon+1, convTime->tm_mday,
            convTime->tm_hour, convTime->tm_min, convTime->tm_sec);

  Serial.print(" from funct: ");
  Serial.println(time_char);

Теперь, когда я вызываю его из моего кода и пытаюсь использовать переменную time tm, это приводит к сбою кода. В приведенном ниже коде я просто пытаюсь вывести его на консоль:

void sendnewNotif()
{
  struct tm *newtime;
  time_t t=182423032;
  iot.convEpoch(t, newtime); // <--- Использование преобразования
  char timeStamp[50];
  // Serial.print(newtime->tm_year);

}

В чем может быть проблема?

Парень

, 👍0

Обсуждение

struct tm newtime; для размещения в стеке. struct tm *newtime — указатель в никуда, @Juraj


1 ответ


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

1
void myIOT32::convEpoch(time_t in_time, struct tm *convTime)
{
  convTime = gmtime(&in_time);

Здесь вы перезаписываете параметр convTime. Нет смысла в передавая такой параметр, если вы не собираетесь использовать предоставленное значение.

void sendnewNotif()
{
  struct tm *newtime;
  time_t t=182423032;
  iot.convEpoch(t, newtime); // <--- Использование преобразования

newtime изначально не инициализирован. Вызов iot.convEpoch() это не меняет (параметр передается по значению, а не по ссылка).

  Serial.print(newtime->tm_year);

Это разыменование неинициализированного указателя, который не определен. поведения и может привести к сбою программы.

Самое простое решение, которое я вижу, — заставить myIOT32::convEpoch() возвращать указатель, полученный от gmtime(). Обратите внимание, что это указывает на статическое хранилище, что делает метод нереентерабельным.

Пример (не проверено):

struct tm *myIOT32::convEpoch(time_t in_time)
{
  struct tm *convTime = gmtime(&in_time);
  // ...
  return convTime;
}

void sendnewNotif()
{
  time_t t = 182423032;
  struct tm *newtime = iot.convEpoch(t);
  Serial.print(newtime->tm_year); 
}
,

спасибо за ваш добрый и исчерпывающий ответ :), но ваш ответ еще больше поднялся: а) какое это имеет значение, если он инициализирован? так как он получает свое значение позже (хотя и как указатель). б) есть ли указания, когда использовать в качестве возвращаемого значения (как вы только что предложили) или, как я сделал, передавая его значение/ссылку (в случае, если он работает так, как ожидалось...) ?, @Guy . D

а) Он не получает свое значение позже. б) В принципе, вы могли бы передать указатель по ссылке, но смешивание указателей и ссылок может быстро привести к путанице., @Edgar Bonet