Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why return a static pointer instead of an out parameter?

Tags:

c

time.h

char* asctime (const struct tm * timeptr);
char* ctime (const time_t * timer);

I found that many functions inside of time.h return pointers to static variables, which could be altered by any subsequent call to those functions. That means I have to copy the data I just got as a result and it's an extra operation I have to execute and that makes those functions thread-unsafe.

Why was it implemented that way? Wouldn't these signatures be better?

void asctime (char * out, const struct tm * timeptr);
void ctime (char * out, const time_t * timer);

We always have to take decisions during development. I'm just asking why they chose to return a static pointer instead of taking an "out variable" as a parameter.

By the way (this is another question), why don't they allocate their result on the heap? Is it to allow the use of anything instead of malloc or just for efficiency?

like image 558
Agustín Nieto García Avatar asked Jul 09 '19 11:07

Agustín Nieto García


2 Answers

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.

like image 50
dbush Avatar answered Oct 17 '22 04:10

dbush


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.

like image 31
Acorn Avatar answered Oct 17 '22 04:10

Acorn