localtime函数中的返回指针的思考

localtime和gmtime这两个函数采用了time.h中的一个tm结构体:

struct tm
{
  int tm_sec;           /* Seconds. [0-60] (1 leap second) */
  int tm_min;           /* Minutes. [0-59] */
  int tm_hour;          /* Hours.   [0-23] */
  int tm_mday;          /* Day.     [1-31] */
  int tm_mon;           /* Month.   [0-11] */
  int tm_year;          /* Year - 1900.  */
  int tm_wday;          /* Day of week. [0-6] */
  int tm_yday;          /* Days in year.[0-365] */
  int tm_isdst;         /* DST.     [-1/0/1]*/

};


这两个函数的原型为:

struct tm *localtime(const time_t *timep);

struct tm *gmtime(const time_t *timep);

 

例1:
---------------------------------------------------------

#include <ctime>
#include <iostream>

using namespace std;


void cur_time(void)
{
 char *wday[] = {"星期天", "星期一","星期二","星期三","星期四","星期五","星期六"};

 time_t timep;
 struct tm *p;

 time(&timep);

 p = localtime(&timep);

 printf("%d年%2d月%2d日", (1900 + p->tm_year), (1 + p->tm_mon), p->tm_mday);
 printf("%s%2d:%2d:%2d/n", wday[p->tm_wday], p->tm_hour, p->tm_min, p->tm_sec);
}

int main()
{
 cur_time();

 return 0;
}

---------------------------------------------------------

运行结果为:

2008年12月26日星期三 11:07:15


例2《一个关于localtime函数的讨论》:

---------------------------------------------------------
#include <ctime>
#include <iostream>

using namespace std;

struct tm* get_local_time()
{
 struct tm *now;
 time_t timep;

 time(&timep);

 now = localtime(&timep);

 return now;
}

int main()
{
 struct tm *temp;
 struct tm *temp1;

 //struct tm tm1;
 //struct tm tm2;

 temp = get_local_time();
        //tm1 = *temp;

 printf("%d:%2d:%2d/n", temp->tm_hour, temp->tm_min, temp->tm_sec);

 //目的是停顿一下
 getchar();
 //tm2 = *temp1;
 temp1 = get_local_time();

 printf("%d:%2d:%2d/n", temp->tm_hour, temp->tm_min, temp->tm_sec);
 printf("%d:%2d:%2d/n", temp1->tm_hour, temp1->tm_min, temp1->tm_sec);

 //printf("%d:%2d:%2d/n", temp->tm_hour, temp->tm_min, temp->tm_sec);
 //printf("%d:%2d:%2d/n", temp1->tm_hour, temp1->tm_min, temp1->tm_sec);

 return 0;
}

---------------------------------------------------------

运行结果为:

最后两个printf()结果是一样的

其原因如下:
这是localtime函数实现的问题。
该函数返回的是一个指针,表示某一个地址。大家知道,如果是一个非静态的局部变量,返回它的地址是错误的做法,因为非静态的局部变量在函数返回时,已经被销毁了,它的地址成为无用的地址。因此localtime函数返回的指针只有以下三种可能:要么是一个静态变量的地址,要么是一个全局变量的地址,或者是使用malloc等函数在堆上分配的空间。

对于最后一种情况,因为标准并没有规定可以对localtime返回的地址进行free,所以如果localtime函数是使用malloc函数分配空间的话,程序员不会使用free函数去释放它,因此造成内存泄露,这是不好的做法。
前两种情况其实是非常相似的,这里仅以第一种情况来做说明。如果localtime函数使用静态变量,则它大致像下面这个样子:
struct tm* localtime(const time_t* ptr)
{
    static struct tm ret;
    // 在这里计算并得到ret的值
    return &ret;
}
如果真是这样的话,不论调用多少次localtime,则它返回的地址都是一样的。只是地址中保存的内容可能不同而已。

比较正确的做法是:
struct tm* temp;
struct tm* temp1;
struct tm tm1;
struct tm tm2;
temp = get_local_time();
tm1 = *temp;
sleep(3);
temp1 = get_local_time();
tm2 = *temp1;
则虽然可能有temp == temp1,但是tm1和tm2则会不同。

静态变量在进行多线程编程时是危险的,因此微软搞出了一个新的localtime_s函数来取代localtime函数(新版本的VC有这个函数,VC 6.0则似乎没有,linux系统我并不清楚)。这两个函数在功能上一致,只是localtime返回地址,而localtime_s是传入一个地址,让函数填充其内容。后者不需要使用静态变量,在多线程的情况下更安全。


例3 用localtime_s()代替localtime():

---------------------------------------------------------
#include <ctime>
#include <iostream>

using namespace std;

int main()
{
 
 struct tm newtime;
 time_t timep;
 errno_t err;

 time(&timep);
 err = localtime_s(&newtime, &timep);
 if (err)
 {
  printf("Invalid argument to localtime_s.");
        return;
 }
 else
 {
  printf("%d:%2d:%2d/n", newtime.tm_hour, newtime.tm_min, newtime.tm_sec);
 }

 return 0;
}

---------------------------------------------------------

例4 gmtime()函数

---------------------------------------------------------

#include <ctime>
#include <iostream>

using namespace std;

void cur_time(void)
{
 char *wday[] = {"星期天", "星期一","星期二","星期三","星期四","星期五","星期六"};

 time_t timep;
 struct tm *p;

 time(&timep);

 p = gmtime(&timep);

 printf("%d年%2d月%2d日", (1900 + p->tm_year), (1 + p->tm_mon), p->tm_mday);
 printf("%s%2d:%2d:%2d/n", wday[p->tm_wday], p->tm_hour + 8, p->tm_min, p->tm_sec);
}

int main()
{
 cur_time();

 return 0;
}

你可能感兴趣的:(多线程,编程,linux,struct,微软)