0

I need to create a converter from epoch time stored in a time_t variable, to a struct tm variable, in order to check / create a certain task every hour or a day. This function should get also a past time_t for other uses.

Converting function, inside a library, works OK ( last two lines are for verification purposes, meaning conversion was done as expected ):

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);

Now, when calling it from my code and try to use time tm var, it causes the code to crash. In code below, I just try to print it to console:

void sendnewNotif()
{
  struct tm *newtime;
  time_t t=182423032;
  iot.convEpoch(t, newtime); // <--- Using the conversion
  char timeStamp[50];
  // Serial.print(newtime->tm_year); 

}

What may be the problem ?

Guy

  • struct tm newtime; to alocate on stack. struct tm *newtime is a pointer to nowhere – Juraj Jun 14 at 10:53
1
void myIOT32::convEpoch(time_t in_time, struct tm *convTime)
{
  convTime = gmtime(&in_time);

Here you are overwriting the parameter convTime. There is no point in passing such a parameter if you are not going to use the value provided.

void sendnewNotif()
{
  struct tm *newtime;
  time_t t=182423032;
  iot.convEpoch(t, newtime); // <--- Using the conversion

newtime is initially uninitialized. The call to iot.convEpoch() doesn't change that (the parameter is passed by value, not by reference).

  Serial.print(newtime->tm_year);

This is dereferencing an uninitialized pointer, which is undefined behavior and can crash the program.

The simplest solution I see is to have myIOT32::convEpoch() return the pointer it got from gmtime(). Note that this points to static storage, which makes the method not reentrant.

Example (not tested):

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); 
}
| improve this answer | |
  • thank you for your kind and comprehensive reply :), but your answer rised some more: a) why does it matter if it is initialized ? since it get its value later on ( though as a pointer ). b) are there guide lines when to use as a return value ( as you just suggested ) or as I did, passing its value/ reference ( in a case it works as expected... ) ? – Guy . D Jun 14 at 13:22
  • a) It does not get it's value later on. b) You could in principle pass the pointer by reference, but mixing pointers and references can quickly become highly confusing. – Edgar Bonet Jun 14 at 15:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.