处理64/32位time_t的便携方式

16
我有一些代码,可以在Windows和Linux上构建。此时,Linux始终是32位的,而Windows则是32位和64位的。Windows希望time_t为64位,而Linux仍然将其作为32位处理。我对此没有意见,除非在某些地方将time_t值转换为字符串。因此,当time_t为32位时,应使用%d进行转换,而当它为64位时应使用%lld...
有什么聪明的方法可以解决这个问题吗?另外:您有什么办法可以找到所有将time_t传递给printf风格函数的地方来解决这个问题吗?
编辑: 我想到了将TT_FMT声明为%d%lld,然后将我的printf更改为以下内容。
printf("time: %d, register: blah")

成为
printf("time: " TT_FMT ", register: blah")

有没有更好的方法?我要如何找到它们全部呢?

实际上,我认为你想要使用无符号格式说明符。 - Tim Post
2
Tim,它在Linux和Windows上都有签名(参见https://dev59.com/anRB5IYBdhLWcg3w6LV3)。否则,它将无法表示Dennis Ritchie的整个生活。 ;) (http://en.wikipedia.org/wiki/Unix_time#Representing_the_number) - Matthew Flaschen
2
实际上,在现代的Linux x86_64上,time_t也是64位宽度的。 - user562374
仅限64位Linux上的@user562374。32位glibc刚刚在版本2.32中支持了64位time_t。 - phuclv
决定 time_t 大小的并不是 Windows,而是你所使用的 C 库。例如,在 MSVC 中,你可以定义 _USE_32BIT_TIME_T 来强制使用 32 位时间。然而,我相当确定断言“Linux 在这一点上总是 32 位”是不正确的。情况比那更复杂! - Clifford
4个回答

11
根据C标准,time_t是算术类型,“能够表示时间”。因此,例如它可以是 double 。(Posix 更明确地提到了这一点,并且还保证 time()返回自Epoch以来的秒数,但后者不被C标准保证。)
也许最清晰的解决方案是将值转换为所需的任意类型之一。您可能需要其中的 unsigned long long unsigned long 之一:
printf("%llu\n", (unsigned long long)t);

这对我来说一直是最清晰的方法。即使只是从strftime中的%c行为,printf没有包括一个格式说明符用于time_t值似乎有点可惜。 - caf
1
谢谢,我觉得很不错,除了time_t是有符号的; 我可能会使用int64_t。 - MK.
1
%jdintmax_t怎么样? - S.S. Anne
1
@JL2210 是的,那应该可以行得通..虽然我认为"%" PRIdMAX可能更加通用。 - Alok Singhal

7
我认为唯一真正可移植的方法是使用 strftimetime_t 转换为字符串。
如果您确定只在 time_tint 的平台上操作,您可以将其强制转换为 intmax_t(来自 stdint.h),并使用 PRIdMAX(来自 inttypes.h)进行打印。

2
现在(距离这个答案9年后),您可以使用%jd代替PRIdMAX,例如snprintf(str, sizeof(str), "%jd", (intmax_t)i_am_a_time_t_var) - John Hascall

3

如果你想使用宏指定符,我建议做一个小调整。不要将整个指定符封装起来,而是只封装修饰符:

#ifdef 64_BIT_TIME
  #define TT_MOD "ll"
#else
  #define TT_MOD ""
#endif

然后像这样使用它:

printf("current time in seconds is: %" TT_MOD "u", time(0));

原因是,虽然你主要想要十进制的第二个数字,但偶尔可能需要十六进制(或者你想要前导0)。只有使用修饰符,你可以轻松地编写:

"%" TT_MOD "x"   // in hex
"%08" TT_MOD "d"  // left pad with 0's so the number is at least 8 digits

4
小小的建议:宏名称不能以数字开头。我可能会使用类似于<inttypes.h>中的名称,而不侵犯保留的命名空间(ISO/IEC 9899:2011 §7.31.6规定:“可以将以PRI或SCN和小写字母或X开头的宏添加到<inttypes.h>头文件中定义的宏中。”)。 - Jonathan Leffler

-1

稍微调整一下Alok的回答,它在Windows和Linux上都是签名的,因此:

printf("%lld\n", t);

更简洁。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接