什么是最终的time_t类型定义?

我在Linux中搜索,看到它是typedef

typedef __time_t time_t; 

但找不到__time_t定义。

time_t维基百科文章文章阐明了这一点。 底线是在C规范中不保证time_t的类型。

time_t数据类型是ISO C库中用于存储系统时间值的数据类型。 这些值是从标准的time()库函数返回的。 这个类型是在标准头文件中定义的一个typedef。 ISO C将time_t定义为算术类型,但不指定任何特定的类型 ,范围,分辨率或编码。 还未指定应用于时间值的算术运算的含义。

Unix和POSIX兼容的系统将time_t类型实现为有signed integer (通常为32或64位宽),表示自 1970年1月1日午夜(不计闰秒) 的Unix纪元开始以来的秒数。 一些系统正确处理负时间值,而另一些则不正确。 使用32位time_t类型的系统容易受到2038年问题的影响 。

[root]# cat time.c

 #include <time.h> int main(int argc, char** argv) { time_t test; return 0; } 

[root]# gcc -E time.c | grep __time_t

typedef long int __time_t;

它在$INCDIR/bits/types.h定义:

 # 131 "/usr/include/bits/types.h" 3 4 # 1 "/usr/include/bits/typesizes.h" 1 3 4 # 132 "/usr/include/bits/types.h" 2 3 4 

答案肯定是特定于实现的。 要明确地找到您的平台/编译器,只需在您的代码中添加此输出:

 printf ("sizeof time_t is: %d\n", sizeof(time_t)); 

如果答案是4(32位),并且你的数据要超过2038 ,那么你有25年的时间来迁移你的代码。

如果将数据存储为字符串,则数据将会正常工作,即使它是这样简单的:

 FILE *stream = [stream file pointer that you've opened correctly]; fprintf (stream, "%d\n", (int)time_t); 

然后用相同的方法读取它(fread,fscanf等等),并且你有你的纪元偏移时间。 .Net中存在类似的解决方法。 我在Win和Linux系统之间传递了64位的时代数字(通过通信渠道)。 这带来了字节顺序问题,但这是另一个主题。

为了回答paxdiablo的查询,我会说它打印了“19100”,因为程序是这样写的(我承认自己在80年代就这样做了):

 time_t now; struct tm local_date_time; now = time(NULL); // convert, then copy internal object to our object memcpy (&local_date_time, localtime(&now), sizeof(local_date_time)); printf ("Year is: 19%02d\n", local_date_time.tm_year); 

printf语句打印固定字符串“Year is:19”,后面跟着“1900年以来的年份”(定义tm->tm_year )的零填充字符串。 在2000年,这个数值显然是100。 "%02d"两个零,但不超过两位数时截断。

正确的方法是(只改变到最后一行):

 printf ("Year is: %d\n", local_date_time.tm_year + 1900); 

新问题:这个想法的理由是什么?

标准

威廉·布伦德尔 ( William Brendel)引用了维基百科(Wikipedia)的话,但是我更喜欢它的马嘴。

C99 N1256标准草案 7.23.1 / 3“时间要素”说:

声明的类型是size_t(在7.17中描述)clock_t和time_t,它们是能够表示时间的算术类型

6.2.5 / 18“类型”说:

整型和浮点类型统称为算术类型。

POSIX 7 sys_types.h说:

[CX] time_t应该是一个整数类型。

其中[CX] 定义为 :

[CX]扩展到ISO C标准。

这是一个扩展,因为它提供了一个更强有力的保证:浮点数。

gcc单行

不需要像Quassnoi提到的那样创建一个文件:

 echo | gcc -E -xc -include 'time.h' - | grep time_t 

在Ubuntu 15.10 GCC 5.2上,前两行是:

 typedef long int __time_t; typedef __time_t time_t; 

在Visual Studio 2008下,它默认为__int64除非您定义_USE_32BIT_TIME_T 。 你最好假装自己不知道它的定义是什么,因为它可以(也将会)从平台变成平台。

time_t在64位机器上是long int类型,否则它是long long int

你可以在这些头文件中验证这个:

time.h/usr/include
types.htypesizes.h/usr/include/x86_64-linux-gnu/bits

(下面的语句不是一个接一个的,它们可以在使用Ctrl + F搜索的头文件中找到)。

1)在time.h

 typedef __time_t time_t; 

2)在types.h

 # define __STD_TYPE typedef __STD_TYPE __TIME_T_TYPE __time_t; 

3)在typesizes.h

 #define __TIME_T_TYPE __SYSCALL_SLONG_TYPE #if defined __x86_64__ && defined __ILP32__ # define __SYSCALL_SLONG_TYPE __SQUAD_TYPE #else # define __SYSCALL_SLONG_TYPE __SLONGWORD_TYPE #endif 

4)再次在types.h

 #define __SLONGWORD_TYPE long int #if __WORDSIZE == 32 # define __SQUAD_TYPE __quad_t #elif __WORDSIZE == 64 # define __SQUAD_TYPE long int #if __WORDSIZE == 64 typedef long int __quad_t; #else __extension__ typedef long long int __quad_t; 

这是大多数传统平台上的32位有符号整数类型。 但是,这会导致你的代码遭受2038年的错误 。 所以现代的C库应该把它定义为一个有符号的64位整数,这是几十亿年的安全。

通常,您会bitsasm头文件目录中找到这些针对gcc的特定于实现的typedef。 对我来说,是/usr/include/x86_64-linux-gnu/bits/types.h

您可以只使用grep,或使用Quassnoi建议的预处理器调用来查看哪个特定的头文件。

time_t只是8个字节( long long/__int64 )的typedef ,所有编译器和操作系统都能理解。 早在几天前,它曾经只是long int (4字节),但现在不是。 如果你看看crtdefs.h中的time_t ,你会发现这两个实现,但操作系统将使用long long