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
1 Answer 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);
}
-
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... ) ?guyd– guyd2020年06月14日 13:22:11 +00:00Commented Jun 14, 2020 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– Edgar Bonet2020年06月14日 15:11:50 +00:00Commented Jun 14, 2020 at 15:11
struct tm newtime;
to alocate on stack.struct tm *newtime
is a pointer to nowhere