char* asctime (const struct tm * timeptr);
char* ctime (const time_t * timer);
Run Code Online (Sandbox Code Playgroud)
我发现在time.h
指向静态变量的返回指针中有许多函数,可以通过对这些函数的任何后续调用来更改它们。这意味着我必须复制刚得到的数据,这是我必须执行的额外操作,这会使那些函数成为线程不安全的。
为什么以这种方式实施?这些签名会更好吗?
void asctime (char * out, const struct tm * timeptr);
void ctime (char * out, const time_t * timer);
Run Code Online (Sandbox Code Playgroud)
在开发过程中,我们始终必须做出决定。我只是在问为什么他们选择返回静态指针而不是将“输出变量”作为参数。
顺便提一句(这是另一个问题),为什么他们不将结果分配到堆上?是允许使用任何东西代替malloc还是仅仅为了提高效率?
dbu*_*ush 22
ctime
and asctime
函数的规范可以追溯到C89,那时候所做的事情有些不同,主要是因为多处理器系统不是很常见,因此使用静态缓冲区不会造成大问题。
最有可能的是,它们没有返回动态分配的内存,因为这要花费额外的时间,并且在那些日子里,CPU周期更难实现。
如果您使用的是Linux之类的POSIX系统,则还有其他两个可用功能,它们基本上就是您描述的替代功能:
char *asctime_r(const struct tm *tm, char *buf);
char *ctime_r(const time_t *timep, char *buf);
Run Code Online (Sandbox Code Playgroud)
这些函数采用指向可以接收输出的缓冲区的指针(并且它们返回指向该相同缓冲区的指针)。该_r
后缀的意思是“折返”,这意味着它可以安全地在多线程程序或者叫做或多于一次没有序列点之间。
Aco*_*orn 12
这意味着我必须复制刚得到的数据
为什么需要复制它?
请注意,即使您在获得数据后立即将其复制,您仍然可以参加比赛。
为什么以这种方式实施?
因为当它们标准化(1989年)时,即使自大型机时代以来就存在多线程,大多数软件也不是多线程的。作为参考,甚至在POSIX线程比这些功能晚了几年(1996)。电脑的速度每年都在增长,并且多核/ SMT处理器直到2001 - 2006年才出现,这并没有帮助。
如果您需要其他功能,则可以始终使用系统特定的功能。
他们为什么不将结果分配到堆上?
分配非常昂贵。
是允许使用任何东西代替malloc还是仅仅为了提高效率?
不知道那是什么意思。正确的方法是将指针传递到目标缓冲区,以便用户选择要使用的分配方法。
您(几乎)描述了_s
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);
Run Code Online (Sandbox Code Playgroud)
如果指定的位置足够大,它们将写入指定的位置,否则将报告错误。
您不需要malloc
这些调用的缓冲区,因为您知道char buf[26];
确实需要什么。
C是1970年代初的产品,这种遗产在这种事情上表现出来。 strtok
还使用静态缓冲区,并且既不是线程安全的也不是可重入的。
对于为什么以这种方式实现这些功能,我还没有明确的解释。可能是为了节省堆栈空间(当时128 kB是很多非常昂贵的内存),可能是为了避免对目标缓冲区的大小或有效性进行运行时检查,等等。C最初是为系统编程设计的,因此,如果要进行大量的时间计算,则可以看到这种方法在一天中节省了大量的周期。
不幸的是,这只是我的推测。我同意传递目标缓冲区是更好的解决方案,这应该是前进的道路。