【问题标题】:localtime() crashes when pass value >0x7FFFFFFF当传递值 >0x7FFFFFFF 时 localtime() 崩溃
【发布时间】:2021-05-17 20:29:27
【问题描述】:

据我了解time_t rawtime = 0xffFFffFF是GMT: Sunday, February 7, 2106 6:28:15 AM

但下面的程序在某些编译器中会带来Thu 1970-01-01 02:59:59 MSK,而在其他编译器中会崩溃。

int main() 
{

    time_t rawtime = 0xffFFffFF;
    struct tm  ts;
    char       buf[80];

    ts = *localtime(&rawtime);
    strftime(buf, sizeof(buf), "%a %Y-%m-%d %H:%M:%S %Z", &ts);
    printf("%s\n", buf);
    return 0;
}

rawtime >0x7fFFffFF 时出现错误行为。为什么?如何解决?

更新: 我需要有一系列警报并在时间到来时采取行动。这是嵌入式系统,我无法为复杂的数据类型提供内存和资源。

【问题讨论】:

  • 使用具有更大 time_t 的不同编译器?
  • time_t 已签名,因此所有高于 0x7fffffff 的值为负数
  • @qrdl 可以签名也可以不签名
  • 本地时间崩溃 可能不准确。在取消引用之前没有检查 localtime 的返回值这一事实更有可能是导致崩溃的原因。
  • @M.M time_t 通常在大多数平台上都已签名,因此我们有 2038 年的问题

标签: c time-t


【解决方案1】:

在大多数平台上,time_t 类型是有符号整数。同样在大多数平台上,time_t 从 1970 年 1 月 1 日开始计算时间。结合这两个事实,我们得到对应于 1970 年 1 月 1 日之前日期的负 time_t 值。

如果您机器上的time_t 是有符号的32 位整数,则0xffffffff 为-1。因此,理论上,该值对应于 1969 年 12 月 31 日的 23:59:59 UTC,即 UTC 午夜前一秒。但在某些情况下,-1 表示错误。因此,尽管我从未遇到过它,但如果有一个 localtime() 实现将 input 上的值 -1 视为错误,我并不完全感到惊讶。

你说它“崩溃了”,但这部分是你的错。 localtime 通过返回空指针表示失败。所以写起来更安全

struct tm *ts;

ts = localtime(&rawtime);
if(ts == NULL) {
    fprintf(stderr, "localtime failed\n");
    exit(1);
}

strftime(buf, sizeof(buf), "%a %Y-%m-%d %H:%M:%S %Z", ts);

如果time_t 是带符号的 32 位值,则其最大值为 2147483647(仍假设 Unix 纪元为 1970 年)对应于 2038 年 1 月 19 日 03:14:07 UTC。最小值 2147483648 对应于 1901 年 12 月 13 日 20:45:52 UTC。

你是对的,如果 time_t 被视为无符号,则最大 32 位值将是 4294967295,并且对应于你提到的 2106 年的日期和时间。

如果time_t 是 64 位类型,因为它越来越流行(并且或多或少有必要阻止y2.038k problem),最大值是如此之大以至于它实际上毫无意义。 (它太大了,以至于年 甚至不能用 32 位表示。)

最后,值得记住的是time_t 的解释是特定于平台的。从理论上讲,它不一定要计算秒数,不一定要从 1970 年 1 月 1 日开始计算,甚至不一定是整数。即使这些事实确实成立,也没有规则说time_t 必须必须签名,因此在为广泛可移植性而设计的程序中,我不会指望有对应于 1901-1970 的值,因为毕竟在某些平台上它们可能对应于 2038-2106。

【讨论】:

    【解决方案2】:

    time_t 的类型和范围是实现定义的,没有最低要求。可以是有符号、无符号、32位、64位、浮点等。

    如果您使用的编译器没有满足您要求的time_t,您可以:

    • 使用不同的编译器,或者
    • 避免使用time_t,或者
    • 重组您的程序,使其在编译器上的time_t 限制范围内工作。

    如 cmets 中所述,“崩溃”可能是由于 localtime 由于输入超出范围而返回空指针,而您在未先检查空值的情况下取消引用它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-10-17
      • 2016-12-25
      • 1970-01-01
      • 1970-01-01
      • 2020-02-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多