小心C语言时间函数陷阱
当前位置:以往代写 > C/C++ 教程 >小心C语言时间函数陷阱
2019-06-13

小心C语言时间函数陷阱

小心C语言时间函数陷阱

副标题#e#

在编写C语言的应用措施时,为了获取可能打印一些跟时间有关的信息,我们常常会利用到C语言自带的一 些时间函数,诸如:time、localtime、ctime、mktime和asctime等。但你大概没有留意到这内里含有一些有 趣的现象,先来看一个例子:

1 #include <stdio.h>
2 #include <time.h>
3
4 int main ()
5 {
6
7 time_t time_1, time_2;
8 struct tm *tm_1, *tm_2, *tm_3;
9 struct tm tm_4, tm_5;
10
11 printf("-------------------- PART I -------------------\n");
12
13 time_1 = time(NULL);
14 sleep(3);
15 time_2 = time(NULL);
16 printf("time1:%d time2:%d\n",time_1,time_2);
17
18 tm_1 = (struct tm*)localtime(&time_1);
19 tm_2 = (struct tm*)localtime(&time_2);
20 tm_3 = (struct tm*)localtime(&time_1);
21
22 printf("tm_1 ptr:%p tm_2 ptr:%p tm_3 ptr:%p\n",tm_1,tm_2,tm_3);
23 printf("asctime(tm_1):%s",asctime(tm_1));
24 printf("asctime(tm_2):%s",asctime(tm_2));
25 printf("asctime(tm_3):%s",asctime(tm_3));
26 }

在看这段代码的输出功效之前,先问各人两个问题:

 (1) 第22行,struct tm布局体 tm_1、tm_2 和tm_3的值有什么干系?

 (2) 第23-26行的输出功效中,tm_2的时间真的比tm_1晚3秒吗?

接下来 ,我们来看一下这段代码的输出功效:

——————– PART I ——————-

time1:1340256774 time2:1340256777

tm_1 ptr:0xfec6f48 tm_2 ptr:0xfec6f48 tm_3 ptr:0xfec6f48

asctime(tm_1):Thu Jun 21 01:32:54 2012

asctime(tm_2):Thu Jun 21 01:32:54 2012

asctime(tm_3):Thu Jun 21 01:32:54 2012

这里的打印功效是否跟你前面预想的一样呢?没错 ,第22行中的tm_1、tm_2和tm_3其实指向的是同一个地点。在localtime函数的实现中,回收了一个静态内部 struct tm布局体来存储对应的时间信息。每次对localtime函数的挪用,都将会修改内部这个struct tm布局 体,也就是说,这个布局体将只会生存最新的挪用功效。因此,localtime每次返回的struct tm布局体也将是 同一个,即指向的地点是同一个。这也就意味着,后续第23行到第25行对asctime的挪用中,实际上传入的都 是同一个布局体(指向同一个地点的指针),功效它们打出来的时间一样也就不敷为奇了。

我们再来 看以下这段代码:

1 #include <stdio.h>
2 #include <time.h>
3
4 int main ()
5 {
6
7 time_t time_1, time_2;
8 struct tm *tm_1, *tm_2, *tm_3;
9 struct tm tm_4, tm_5;
10
11 printf("-------------------- PART I -------------------\n");
12
13 time_1 = time(NULL);
14 sleep(3);
15 time_2 = time(NULL);
16 printf("time1:%d time2:%d\n",time_1,time_2);
17
18 tm_1 = (struct tm*)localtime(&time_1);
19 tm_2 = (struct tm*)localtime(&time_2);
20 tm_3 = (struct tm*)localtime(&time_1);
21
22 printf("tm_1 ptr:%p tm_2 ptr:%p tm_3 ptr:%p\n",tm_1,tm_2,tm_3);
23 printf("asctime(tm_1):%s",asctime(tm_1));
24 printf("asctime(tm_2):%s",asctime(tm_2));
25 printf("asctime(tm_3):%s",asctime(tm_3));
26
27
28 printf("-------------------- PART II -------------------\n");
29
30 time_1 = time(NULL);
31 sleep(3);
32 time_2 = time(NULL);
33 printf("time1:%d time2:%d\n",time_1,time_2);
34
35 tm_4 = *((struct tm*)localtime(&time_1));
36 tm_5 = *((struct tm*)localtime(&time_2));
37
38 printf("tm_4 ptr:%p tm_5 ptr:%p\n",&tm_4,&tm_5);
39 printf("tm_4 sec:%d tm_5 sec:%d\n",tm_4.tm_sec,tm_5.tm_sec);
40
41 printf("asctime(&tm_4):%sasctime(&tm_5):%s",asctime(&tm_4),asctime (&tm_5));
42 printf("asctime(&tm_4) ptr:%p asctime(&tm_5) ptr:%p\n",asctime (&tm_4),asctime(&tm_5));
43
44 printf("asctime(&tm_4):%s",asctime(&tm_4));
45 printf("asctime(&tm_5):%s",asctime(&tm_5));


#p#副标题#e#

在第28行之前跟上面的示例代码是一样,这里就不再冗述,我们主要来看剩余部门。既然在前面我们已经 知道了localtime返回的是同一个内部静态布局的地点,那么我们不禁想到可以将它赋值给当地布局体,这样 前面临localtime函数的返回值可以获得生存,不会被后头的挪用所包围,如第35和36行所示。那么,我们不 禁想问:第41行打印出来的布局体tm_4和tm_5对应的时间功效跟第44-45行打印出来的一样么?

我们来 看一下PART II的输出功效:

——————– PART II ——————-

time1:1340256777 time2:1340256780

tm_4 ptr:0xffe82dd8 tm_5 ptr:0xffe82e08

tm_4 sec:57 tm_5 sec:0

asctime(&tm_4):Thu Jun 21 01:33:00 2012

asctime(&tm_5):Thu Jun 21 01:33:00 2012

asctime(&tm_4) ptr:0xfec59dc asctime(&tm_5) ptr:0xfec59dc

asctime (&tm_4):Thu Jun 21 01:32:57 2012

asctime(&tm_5):Thu Jun 21 01:33:00 2012

#p#分页标题#e#

输出结 果跟你的预期一样么?我们诧异地发明,第41行打印的功效中,tm_4和tm_5的时间字符串是一样的。但我们通 过打印出tm_4和tm_5布局体的地点,以及对应的秒数(tm.sec),都可以让我们确信这次tm_4和tm_5是两个不 同的时间布局体。问题其实出在asctime函数中,通过打印asctime挪用tm_4和tm_5布局体后返回的指针地点, 我们发明这两个地点是一样的。从asctime函数的行为,我们不难遐想到,其实它的内部实现跟localtime雷同 ,它也利用了一个内部静态字符数组来生存转换好的时间字符串。每次对asctime的挪用,都将修改这个字符 串,而函数每次都将返回同一个地点,即内部静态字符数组的地点。

下面我们来阐明一下第41行的行 为:

1) 挪用asctime(&tm_4),凭据tm_4的信息更新内部静态字符数组,返回字符数组的地点;

2) 挪用asctime(&tm_5),凭据tm_5的信息更新内部静态字符数组,返回字符数组的地点。在这一步中 ,新的tm_5的信息将会包围掉本来tm_4的那些信息。

3) 打印第一个参数指向地点的字符串,即该内部静态 字符数组。此时这个字符串已经被更新为tm_5的信息了,因此,将打印tm_5对应的时间信息。

4) 打印第二 个参数指向地点的字符串,即tm_5对应的时间信息。

而在第44行中,我们在挪用asctime函数后,随即 将信息打印出来,此时则为tm_4的时间信息。同理,跟我们对localtime函数的操纵雷同,我们也可以通过本 地字符数组来生存asctime函数的挪用功效,从而制止功效被后续的挪用所包围。

按照POSIX尺度,时 间函数asctime()、ctime()、gmtime()和localtime()函数都将返回内部静态工具,要么是struct tm布局体, 要么是字符数组。因此,在对这些函数的挪用时,我们需要特另外小心,假如不需要生存其挪用功效,我们可 以实时地打印,假如需要生存其挪用功效,可以回收当地布局来姑且存放。

    关键字:

在线提交作业