Answers:
维基百科的time_t文章对此有所启发。底线是time_t
C规范中不能保证的类型。
的
time_t
数据类型是用于存储系统时间值所定义的ISO C库中的数据类型。这些值是从标准time()
库函数返回的。此类型是标准标头中定义的typedef。ISO C将time_t定义为算术类型,但未指定任何特定类型,范围,分辨率或编码。还没有指定应用于时间值的算术运算的含义。兼容Unix和POSIX的系统将
time_t
类型实现为signed integer
(通常为32或64位宽),它表示自Unix纪元开始以来的秒数:1970年1月1日午夜UTC(不计算seconds秒)。一些系统正确处理负时间值,而其他系统则不能。使用32位time_t
类型的系统容易受到2038年问题的影响。
time_t
可能会在磁盘上使用数据结构。但是,由于文件系统经常被其他操作系统读取,因此基于此类依赖于实现的类型来定义文件系统是很愚蠢的。例如,同一文件系统可能同时在32位和64位系统上使用,并且time_t
可能会更改大小。因此,需要更精确地定义文件系统(“ 32位有符号整数给出自1970年初以来的秒数,以UTC开头”),而不是仅仅定义为time_t
。
time.h
。那篇文章的链接cppreference.com但引用内容无处可寻...
time_t
已签名的说法不正确。pubs.opengroup.org/onlinepubs/9699919799/basedefs/…规定各种事物必须是“有符号整数类型”或“无符号整数类型”,但time_t
其中仅表示“必须是整数类型”。一个实现可以使time_t
未签名,并且仍然符合POSIX。
[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
typedef __int32_t __time_t;
和typedef __time_t time_t;
中FreeBSD freebsd-test 8.2-RELEASE-p2 FreeBSD 8.2-RELEASE-p2 #8: Sun Aug 7 18:23:48 UTC 2011 root@freebsd-test:/usr/obj/usr/src/sys/MYXEN i386
。您的结果将像在Linux中那样显式设置(至少在Debian的2.6.32-5-xen-amd64上)。
__time_t
而不要time_t
查找的底层类型time_t
?省略了一步?
typedef __time_t time_t;
,也需要检查周围的代码以确保实际上使用了typedef,而不仅仅是条件编译的一部分。 typedef long time_t;
可能也找到了。
标准品
威廉·布伦德尔(William Brendel)引用了维基百科,但从马的嘴里我更喜欢它。
C99 N1256标准草案 7.23.1 / 3“时间的组成部分”表示:
声明的类型为size_t(在7.17中描述)clock_t和time_t,它们是能够表示时间的算术类型
和6.2.5 / 18“类型”说:
整数和浮点类型统称为算术类型。
[CX] time_t应为整数类型。
其中[CX]
被定义为:
[CX]对ISO C标准的扩展。
这是一个扩展,因为它可以提供更强的保证:浮点数已经存在。
海湾合作委员会一线
无需创建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;
命令分解,并带有以下引号man gcc
:
-E
:“在预处理阶段之后停止;请不要正确运行编译器。”-xc
:指定C语言,因为输入来自没有文件扩展名的stdin。-include file
:“处理文件,就像” #include“ file”“一样显示为主要源文件的第一行。-
:来自stdin的输入gcc -E -xc -include time.h /dev/null | grep time_t
答案肯定是特定于实现的。要明确地为您的平台/编译器找到信息,只需将以下输出添加到代码中:
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等转换为int),就可以得到时间偏移时间。.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”,后跟零填充字符串,并带有“ years since 1900”(的定义tm->tm_year
)。显然,在2000年,该值为100。"%02d"
填充两个零,但如果长度超过两位,则不会截断。
正确的方法是(仅更改为最后一行):
printf ("Year is: %d\n", local_date_time.tm_year + 1900);
新问题:这种想法的依据是什么?
%zu
格式说明符来格式化size_t
值(由产生sizeof
),因为它们是无符号(u
)且长度为size_t(z
)·
printf ("sizeof time_t is: %d\n", (int) sizeof(time_t));
并避免该z
问题。
在Visual Studio 2008下,__int64
除非您定义,否则默认为_USE_32BIT_TIME_T
。您最好假装不知道其定义是什么,因为它可以(并将)在不同平台之间变化。
time_t
是long int
64位计算机上的类型,否则为long long int
。
您可以在以下头文件中对此进行验证:
time.h
:/usr/include
types.h
和typesizes.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;
long int
到处都不是。见stackoverflow.com/questions/384502/...
在大多数旧版平台上,这是32位有符号整数类型。但是,这会使您的代码遭受2038年bug的困扰。因此,现代C库应该将其定义为带符号的64位int,这可以安全使用数十亿年。
通常,您会在bits
或asm
标头目录中找到gcc的这些特定于底层实现的特定typedef 。对我来说,这是/usr/include/x86_64-linux-gnu/bits/types.h
。
您可以只是grep,也可以使用Quassnoi建议的预处理程序调用来查看哪个特定的标头。
最终time_t typedef到底要做什么?
健壮的代码不在乎类型是什么。
C种time_t
是像等的真实类型double, long long, int64_t, int
。
它甚至可能是unsigned
来自多个时间函数的返回值,表明错误不是-1
,而是(time_t)(-1)
-此实现选择并不常见。
关键是这种“需要知道”的类型很少见。应该编写代码以避免这种需要。
但是,当代码想要打印原始文件时,就会发生一种常见的“需要知道”的事情time_t
。转换为最宽的整数类型将适应大多数现代情况。
time_t now = 0;
time(&now);
printf("%jd", (intmax_t) now);
// or
printf("%lld", (long long) now);
强制转换为double
或long double
也可以,但可能会提供不精确的十进制输出
printf("%.16e", (double) now);
double difftime(time_t time1, time_t time0)
了统一的减法方法。
long int
。