Why return a static pointer instead of an out parameter?

That means I have to copy the data I just got as result

Why do you need to copy it?

Note that even if you copy the data as soon as you get it, you will still be open to races.

Why was it implemented that way?

Because when they were standardized (1989), most software wasn't multi-threaded even if multi-threading existed since the mainframe era. For reference, even POSIX threads were standardized years later (1996) than these functions. It did not help either that computers got quicker every single year and multi-core/SMT processors did not appear until 2001-2006.

If you needed something else, you could always use a system-specific function.

why don't they allocate their result on the heap?

Allocating is very expensive.

Is it to allow the use of anything instead of malloc or just for efficiency?

Not sure what you mean by that. The proper way to do this is to pass a pointer to the destination buffer, so that the user chooses what allocation method to use.


The specification of the ctime and asctime functions goes back to C89, and things were done a bit different back in those days, mainly because multi-processor systems weren't very common and thus using a static buffer wouldn't cause a big problem.

Most likely, they didn't return dynamically allocated memory because it took extra time, and in those days CPU cycles were harder to come by.

If you're on a POSIX system like Linux, you have two other functions available which are basically what you described as an alternative:

   char *asctime_r(const struct tm *tm, char *buf);
   char *ctime_r(const time_t *timep, char *buf);

These function take a pointer to a buffer that can receive the output (and they return a pointer to that same buffer). The _r suffix means "reentrant", meaning it can safely be called either in a multithreaded program or more than once without a sequence point in between.


You are (almost) describing the _s variants that were added in C11

errno_t ctime_s(char *buffer, rsize_t bufsz, const time_t *time);
errno_t asctime_s(char *buf, rsize_t bufsz, const struct tm *time_ptr);

These write to the specified location, provided it is big enough, and report the error otherwise.

You don't need to malloc the buffers for these calls, as you know char buf[26]; is exactly what is needed.

Tags:

C

Time.H