为什么 return 是静态指针而不是输出参数?

Why return a static pointer instead of an out parameter?

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

我发现 time.h return 中的许多函数都指向静态变量,可以通过对这些函数的任何后续调用来更改。这意味着我必须复制我刚得到的数据,这是我必须执行的额外操作,这使得这些函数线程不安全。

为什么要这样实施?这些签名不是更好吗?

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

我们总是要在开发过程中做出决定。我只是问他们为什么选择 return 静态指针而不是将 "out variable" 作为参数。

顺便说一句(这是另一个问题),为什么他们不在堆上分配他们的结果?是允许使用任何东西而不是 malloc 还是只是为了效率?

ctimeasctime 函数的规范可以追溯到 C89,当时的做法有点不同,主要是因为 multi-processor 系统不是很常见,因此使用静态缓冲区不会造成大问题。

很可能,他们没有 return 动态分配内存,因为这需要额外的时间,而且在那些日子里 CPU 周期更难获得。

如果您使用的是像 Linux 这样的 POSIX 系统,您还有另外两个可用的功能,基本上就是您描述的替代功能:

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

这些函数采用指向可以接收输出的缓冲区的指针(并且它们 return 指向同一缓冲区的指针)。 _r 后缀表示 "reentrant",这意味着它可以在多线程程序中安全地调用或多次调用,中间没有序列点。

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

为什么要复制它?

请注意,即使您在获得数据后立即复制,您仍然可以参加比赛。

Why was it implemented that way?

因为当它们被标准化时 (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.

如果您需要其他东西,您可以随时使用 system-specific 函数。

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?

不确定你的意思。这样做的正确方法是传递一个指向目标缓冲区的指针,以便用户选择要使用的分配方法。

您(几乎)描述了在 C11

中添加的 _s 变体
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);

这些写入到指定位置,只要它足够大,否则会报错。

您不需要 malloc 这些调用的缓冲区,正如您所知 char buf[26]; 正是所需要的。

C 是 20 世纪 70 年代早期的产物,这种遗产体现在这样的事情上。 strtok 也使用静态缓冲区,既不是 thread-safe 也不是 re-entrant。

对于为什么以这种方式实现这些功能,我还没有看到明确的解释。可能是为了节省堆栈 space(128 kB 在当时是非常昂贵的内存),可能是为了避免运行时检查目标缓冲区的大小或有效性等。C 最初是专为系统编程而设计,因此如果进行大量时间计算,我可以看到这种方法在一天中节省了大量的周期。

不幸的是,这是我的猜测。我同意传递目标缓冲区是更好的解决方案,这应该是前进的道路。