今天在使用ctime函数遇到了一个问题,示例代码如下:
const char *date; //获取当前的时间
time_t now = time(NULL);
date = ctime(&now);
delete_crlf(date); //此函数是为了删除date的换行符
printf("%s\n", date);
sleep(2);
now = time(NULL);
ctime(&now);
printf("%s\n", date);
原本我的目的是为了打印出当前的时间,因此我对于这两个输出的期望都应该是
Mon Nov 13 15:28:25 2017
但最终结果居然是
Mon Nov 13 15:28:25 2017
Mon Nov 13 15:28:27 2017
发现两次打印的结果居然不一致,这是为什么呢?
在http://www.cplusplus.com/reference/ctime/ctime/上查阅函数信息时发现:
The returned value points to an internal array whose validity or value may be altered by any subsequent call to asctime or ctime.
大意是说,它的返回值指向了一个内部数组,而它的值或有效性可能会被之后的函数调用ctime或asctime改变。
函数的具体实现如下:
/* 这里的函数在GNU libc的locale/C-time.c中定义 */
#include <stdio.h>
#include <time.h>
extern const struct locale_data _nl_C_LC_TIME attribute_hidden;
#define ab_day_name(DAY) (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABDAY_1)+(DAY)].string)
#define ab_month_name(MON) (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABMON_1)+(MON)].string)
static const char format[] = "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n";
//result存储最终结果
static char result[ 3+1+3+1+20+1+20+1+20+1+20+1+20+1+1];
static char * asctime_internal (const struct tm *tp, char *buf, size_t buflen)
{
if (tp == NULL)
{
__set_errno (EINVAL);
return NULL;
}
if (__builtin_expect (tp->tm_year > INT_MAX - 1900, 0))
{
eoverflow:
__set_errno (EOVERFLOW);
return NULL;
}
int n = __snprintf (buf, buflen, format,
(tp->tm_wday < 0 || tp->tm_wday >= 7 ?
"???" : ab_day_name (tp->tm_wday)),
(tp->tm_mon < 0 || tp->tm_mon >= 12 ?
"???" : ab_month_name (tp->tm_mon)),
tp->tm_mday, tp->tm_hour, tp->tm_min,
tp->tm_sec, 1900 + tp->tm_year);
if (n < 0)
return NULL;
if (n >= buflen)
goto eoverflow;
return buf;
}
char * __asctime_r (const struct tm *tp, char *buf)
{
return asctime_internal (tp, buf, 26);
}
weak_alias (__asctime_r, asctime_r)
char * asctime (const struct tm *tp)
{
return asctime_internal (tp, result, sizeof (result));
}
libc_hidden_def (asctime)
char * ctime (const time_t *t)
{
return asctime (localtime (t));
}
可以看到,ctime的返回值是result这个静态数组的首地址,因此每一次的ctime调用都会覆盖原来的值。这也就解释了上述情况的问题。
所以说,如果要获取当前人类可读的时间形式,最好是通过定义一个新的字符数组去储存,而不要去定义字符指针,因为你指向的内容很可能会因为其他方式改变了。