localtime() 在传递值 >0x7FFFFFFF 时崩溃
localtime() crashes when pass value >0x7FFFFFFF
据我了解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
从 1970 年 1 月 1 日开始计算时间。结合这两个事实,我们有负的 time_t
值对应于 1970 年 1 月 1 日 之前 的日期。
如果您机器上的 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或多或少是必要的),最大值太大以至于实际上没有意义. (太大了year甚至不能用32位来表示。)
最后,值得记住的是 time_t
的解释是平台特定的。理论上不一定是秒数,不一定是从1970年1月1日算起,甚至不一定是整数。即使这些事实确实成立,也没有规则说 time_t
必须 必须 被签名,所以在一个为广泛的可移植性而设计的程序中我不会指望有价值对应1901-1970,毕竟在某些平台上可能对应2038-2106
time_t
的类型和范围是实现定义的,没有最低要求。可以是有符号、无符号、32位、64位、浮点数等
如果您使用的编译器没有 time_t
范围满足您的要求,您可以:
- 使用不同的编译器,或者
- 避免使用
time_t
,或
- 重构您的程序以在您的编译器
time_t
的限制内工作。
如评论中所述,“崩溃”可能是由于 localtime
由于输入超出范围而返回空指针,而您在没有首先检查空指针的情况下取消引用它。
据我了解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
从 1970 年 1 月 1 日开始计算时间。结合这两个事实,我们有负的 time_t
值对应于 1970 年 1 月 1 日 之前 的日期。
如果您机器上的 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或多或少是必要的),最大值太大以至于实际上没有意义. (太大了year甚至不能用32位来表示。)
最后,值得记住的是 time_t
的解释是平台特定的。理论上不一定是秒数,不一定是从1970年1月1日算起,甚至不一定是整数。即使这些事实确实成立,也没有规则说 time_t
必须 必须 被签名,所以在一个为广泛的可移植性而设计的程序中我不会指望有价值对应1901-1970,毕竟在某些平台上可能对应2038-2106
time_t
的类型和范围是实现定义的,没有最低要求。可以是有符号、无符号、32位、64位、浮点数等
如果您使用的编译器没有 time_t
范围满足您的要求,您可以:
- 使用不同的编译器,或者
- 避免使用
time_t
,或 - 重构您的程序以在您的编译器
time_t
的限制内工作。
如评论中所述,“崩溃”可能是由于 localtime
由于输入超出范围而返回空指针,而您在没有首先检查空指针的情况下取消引用它。