How is the result struct of localtime allocated in C?

15,007

Solution 1

The pointer returned by localtime (and some other functions) are actually pointers to statically allocated memory. So you do not need to free it, and you should not free it.

http://www.cplusplus.com/reference/clibrary/ctime/localtime/

This structure is statically allocated and shared by the functions gmtime and localtime. Each time either one of these functions is called the content of this structure is overwritten.

EDIT : Appending a few things mentioned in the comments.

A direct result of this shared data-structure is that localtime and similar functions are not thread-safe. The thread-safe solution varies with different platforms. localtime_r for POSIX and localtime_s for MSVC.

Solution 2

It returns a pointer to a piece of statically allocated memory (probably either a static variable defined inside localtime or a global defined somewhere in the C runtime library). You must not free such memory.

Obviously this function is not reentrant (but can be thread-safe if TLS is used).

You must be careful when using this pointer: never make any function calls that could call localtime/gmtime/... before you finished using that pointer, otherwise the content of the memory referenced by your pointer could change (in response to the new call to localtime) and you will be reading values relative to another time_t.

In general the design of the date/time library is quite outdated, this kind of optimization was worthwhile when the C language was designed, nowadays it only gives problems.

To address these problems there are at least two different improved versions of these functions: localtime_r (SUSv2, r stays for "reentrant") and localtime_s (Microsoft, s stays for "safe"). The sad fact for portability is that these do almost the same thing (they require the destination struct tm to be passed as a parameter), but differ in name and ordering of the parameters.

Solution 3

The man page says:

The return value points to a statically allocated struct which might be overwritten by subsequent calls to any of the date and time functions.

Also:

The localtime_r() function does the same, but stores the data in a user-supplied struct. It need not set tzname, timezone, and daylight.

Solution 4

Actually localtime usually returns the address of a static object. I suspect it looks like this:

struct tm *
localtime(const time_t *timer)
{
    static struct tm tm;

    /* Magic. */

    return &tm;
}

Solution 5

They return a pointer to a static struct local to the library. From the man page:

NOTES

The  four functions asctime(), ctime(), gmtime() and localtime() return
a pointer to static data and hence are  not  thread-safe.   Thread-safe
versions asctime_r(), ctime_r(), gmtime_r() and localtime_r() are spec‐
ified by SUSv2, and available since libc 5.2.5.

POSIX.1-2001 says: "The asctime(), ctime(), gmtime(),  and  localtime()
functions  shall  return values in one of two static objects: a broken-
down time structure and an array of type char.  Execution of any of the
functions  may  overwrite  the  information returned in either of these
objects by any of the other functions."  This can occur  in  the  glibc
implementation.
Share:
15,007
Akash
Author by

Akash

Tell me and i forget. Teach me and i remember. Involve me and i learn. - Benjamin Franklin

Updated on June 05, 2022

Comments

  • Akash
    Akash almost 2 years

    I was playing with the time.h file in C that helps us with time/day functions.

    I came across:

    struct tm * _Cdecl localtime(const time_t *__timer);
    

    ...which seems to return a pointer to tm struct. I have found that return by address is mostly used to return new memory allocations.

    If this is so, how does the above return actually work (the return address of a struct tm). Is the returned object defined somewhere?

    Thanks

  • ChrisWue
    ChrisWue over 12 years
    You are missing an & I believe
  • ouah
    ouah over 12 years
    @OliCharlesworth actually it has, read (C99, 7.23.3 Time conversions functions) "Except for the strftime function, these functions each return a pointer to one of two types of static objects [...] Execution of any of the functions that return a pointer to one of these object types may overwrite the information in any object of the same type pointed to by the value returned from any previous call to any of them."
  • Brian Roach
    Brian Roach over 12 years
    Might also be good to point out that because of this, it isn't threadsafe and the _r versions of these calls are.
  • Mysticial
    Mysticial over 12 years
    @BrianRoach Yes, that's a very good point. Interestingly, I can't find the _r versions outside of the linux man pages. Nor does it appear in MSVC. Is it a compiler extension?
  • Brian Roach
    Brian Roach over 12 years
    @Mysticial - SUSv2; pubs.opengroup.org/onlinepubs/007908799/xsh/localtime.html . I don't do windows, so I have no idea what the equiv is or if it exists
  • Matteo Italia
    Matteo Italia over 12 years
    @Mysticial: for MSVC there's the equivalent _s version (with parameters swapped); the _r version isn't in the C standard, but it's defined in the Standard UNIX Specification (the man pages refer to SUSv2).
  • Brian Roach
    Brian Roach over 12 years
    man pages are a wonderful thing. At the time SO wasn't showing me that anyone else had answered so I figured I'd just post the relevant docs.
  • Raffi Khatchadourian
    Raffi Khatchadourian over 10 years
    There are no objects in C :)
  • cnicutar
    cnicutar over 10 years
    @RaffiKhatchadourian I am using the word "object" in the same sense the standard is using it.
  • chux - Reinstate Monica
    chux - Reinstate Monica almost 9 years
    Note: gmtime() may return the address of the same static struct tm; as localtime().
  • chux - Reinstate Monica
    chux - Reinstate Monica almost 9 years
    Note: localtime_s() is also detailed in C11 spec: normative section K.3.8.2.4. Not certain if MS (or anyone) meets that C11 specification.
  • Hi-Angel
    Hi-Angel over 2 years
    Wow, good thing you said that! I was doing exactly that: measuring date_before and date_after and comparing them. And now as it turns out I was comparing the same variable! I confirm that printing address of date_before and date_after gives the same value.