【问题标题】:How is the result struct of localtime allocated in C?在 C 中如何分配 localtime 的结果结构?
【发布时间】:2012-01-31 10:27:49
【问题描述】:

我正在使用 C 语言中的 time.h 文件来帮助我们处理时间/日期函数。

我遇到了:

struct tm * _Cdecl localtime(const time_t *__timer);

...这似乎返回了一个指向 tm 结构的指针。我发现按地址返回主要用于返回新的内存分配。

如果是这样,上面的返回实际上是如何工作的(struct tm 的返回地址)。返回的对象是否在某处定义?

谢谢

【问题讨论】:

  • 您在代码中定义和分配 tm 结构 localtime( ) 将其输出存储在该结构中并返回指向同一结构的指针.这似乎是多余的,但有时取回指针很方便,即使您知道结构在哪里。
  • @PeteWilson - 嗯,不,你没有。请参阅下面的答案。您所描述的只是来自SUSv2的_r版本的调用(localtime_r())或MSVC中的_s版本的调用中的情况

标签: c function pointers struct


【解决方案1】:

localtime(和其他一些函数)返回的指针实际上是指向静态分配内存的指针。 所以你不需要释放它,你也不应该释放它。

http://www.cplusplus.com/reference/clibrary/ctime/localtime/

此结构由函数静态分配和共享 gmtime 和本地时间。每次这些功能之一是 调用这个结构的内容被覆盖。

编辑:添加 cmets 中提到的一些内容。

这种共享数据结构的直接结果是localtime 和类似函数不是线程安全的。线程安全的解决方案因平台而异。 localtime_r for POSIXlocaltime_s for MSVC

【讨论】:

  • @OliCharlesworth 实际上它有,阅读(C99,7.23.3 时间转换函数)“除了 strftime 函数,这些函数每个都返回一个指向两种类型的静态对象之一的指针 [... ] 执行返回指向这些对象类型之一的指针的任何函数可能会覆盖任何相同类型的对象中的信息,该对象由任何先前调用它们中的任何一个返回的值所指向。"
  • 或许也可以指出,正因为如此,它不是线程安全的,而这些调用的 _r 版本是。
  • @BrianRoach 是的,这是一个很好的观点。有趣的是,我在 linux 手册页之外找不到 _r 版本。它也没有出现在 MSVC 中。是编译器扩展吗?
  • @Mysticial - SUSv2; pubs.opengroup.org/onlinepubs/007908799/xsh/localtime.html 。我不做 windows,所以我不知道 equiv 是什么或它是否存在
  • @Mysticial:对于 MSVC,有等效的 _s 版本(交换了参数); _r 版本不在 C 标准中,但在标准 UNIX 规范中定义(手册页参考 SUSv2)。
【解决方案2】:

它返回一个指向一块静态分配内存的指针(可能是在 localtime 中定义的 static 变量或在 C 运行时库中某处定义的全局变量)。你不能释放这样的内存。

显然这个函数是不可重入的(但如果使用 TLS 则可以是线程安全的)。

使用该指针时必须小心:在使用完该指针之前,切勿进行任何可能调用localtime/gmtime/...的函数调用,否则指针所引用的内存内容可能会发生变化(响应对localtime 的新调用),您将读取相对于另一个time_t 的值。

一般来说日期/时间库的设计已经过时了,这种优化在设计C语言的时候是值得的,现在只会出问题。

为了解决这些问题,这些函数至少有两个不同的改进版本:localtime_r(SUSv2,r 保留为“可重入”)和localtime_s(Microsoft,s 保留为“安全”) .可移植性的可悲事实是,它们几乎做同样的事情(它们需要将目标 struct tm 作为参数传递),但参数的名称和顺序不同。

【讨论】:

  • 注意:localtime_s() 也在 C11 规范:规范部分 K.3.8.2.4 中有详细说明。不确定 MS(或任何人)是否符合 C11 规范。
  • 哇,你说的太好了!我正是这样做的:测量date_beforedate_after 并比较它们。现在事实证明我在比较同一个变量!我确认date_beforedate_after 的打印地址给出了相同的值。
【解决方案3】:

man page 说:

返回值指向一个静态分配的结构,该结构可能被后续调用任何日期和时间函数覆盖。

还有:

localtime_r() 函数的作用相同,但将数据存储在用户提供的结构中。它不需要设置 tzname、时区和日光。

【讨论】:

    【解决方案4】:

    其实localtime通常会返回一个静态对象的地址。我怀疑它看起来像这样:

    struct tm *
    localtime(const time_t *timer)
    {
        static struct tm tm;
    
        /* Magic. */
    
        return &tm;
    }
    

    【讨论】:

    • 我相信你错过了&
    • C 中没有对象 :)
    • @RaffiKhatchadourian 我使用“对象”一词的含义与标准使用它的含义相同。
    • 注意:gmtime()可能返回与localtime()相同的static struct tm;的地址。
    【解决方案5】:

    它们返回一个指向库本地静态结构的指针。从手册页:

    注意事项
    
    asctime()、ctime()、gmtime() 和 localtime() 这四个函数返回
    指向静态数据的指针,因此不是线程安全的。线程安全
    版本 asctime_r()、ctime_r()、gmtime_r() 和 localtime_r() 是规范的
    由 SUSv2 定义,并且从 libc 5.2.5 开始可用。
    
    POSIX.1-2001 说:“asctime()、ctime()、gmtime() 和 localtime()
    函数应在两个静态对象之一中返回值:一个损坏的-
    停机时间结构和 char 类型的数组。执行任何
    函数可能会覆盖其中任何一个返回的信息
    任何其他函数的对象。”这可能发生在 glibc
    实施。

    【讨论】:

    • 手册页是个好东西。当时 SO 没有告诉我其他人已经回答了,所以我想我只是发布相关文档。
    【解决方案6】:

    localtime 函数返回的指向对象具有静态存储持续时间。

    【讨论】:

      猜你喜欢
      • 2012-01-31
      • 2021-12-05
      • 2012-10-30
      • 1970-01-01
      • 2011-06-14
      • 1970-01-01
      • 1970-01-01
      • 2012-04-01
      • 1970-01-01
      相关资源
      最近更新 更多