【发布时间】:2010-10-03 01:02:53
【问题描述】:
我搜索了我的 Linux 机器并看到了这个 typedef:
typedef __time_t time_t;
但我找不到__time_t 定义。
【问题讨论】:
我搜索了我的 Linux 机器并看到了这个 typedef:
typedef __time_t time_t;
但我找不到__time_t 定义。
【问题讨论】:
您可以使用typeid 来了解time_t 在您的系统中是如何定义的。
#include <iostream> // cout
#include <ctime> // time_t
#include <typeinfo> // typeid, name
using namespace std;
int main()
{
cout << "Test 1: The type of time_t is: \t\t"
<< typeid(time_t).name() << endl;
cout << "Test 2: time_t is a signed long?: \t"
<< (typeid(time_t) == typeid(signed long) ? "true" : "false") << endl;
cout << "Test 3: time_t is an unsigned long?: \t"
<< (typeid(time_t) == typeid(unsigned long) ? "true" : "false") << endl;
return 0;
}
在我的系统中,输出是:
测试一:time_t的类型为:l 测试 2:time_t 是有符号的 long?:true 测试 3:time_t 是无符号长整数?:假【讨论】:
标准
William Brendel引用了维基百科,但我更喜欢从马的嘴里说出来。
C99 N1256 standard draft 7.23.1/3 “时间的组成部分” 说:
声明的类型是 size_t(在 7.17 中描述)clock_t 和 time_t,它们是能够表示时间的算术类型
和 6.2.5/18 “类型” 说:
整数和浮点类型统称为算术类型。
[CX] time_t 应为整数类型。
其中[CX] 是defined as:
[CX] 对 ISO C 标准的扩展。
它是一个扩展,因为它提供了一个更强大的保证:浮点数不存在。
gcc 单线
不需要像by 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 语言,因为输入来自没有文件扩展名的标准输入。-include file: "处理文件好像 "#include "file"" 出现在主要源文件的第一行。"-: 标准输入输入【讨论】:
gcc -E -xc -include time.h /dev/null | grep time_t
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)。
time_t 在 64 位机器上为 long int 类型,否则为 long long int。
您可以在这些头文件中验证这一点:
time.h:/usr/includetypes.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/…
答案肯定是特定于实现的。要确定您的平台/编译器,只需在代码中的某处添加此输出:
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 中),你就有了你的 epoch 偏移时间。 .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 问题。
time_t Wikipedia article 文章对此有所了解。底线是 time_t 的类型在 C 规范中没有得到保证。
time_t数据类型是 为存储而定义的 ISO C 库 系统时间值。这些值是 从标准返回time()库函数。这种类型是 标准中定义的 typedef 标题。 ISO C 定义 time_t 作为算术类型,但确实 不指定任何特定类型, 范围、分辨率或编码。 也未指定的含义是 应用于时间的算术运算 价值观。Unix 和 POSIX 兼容系统将
time_t类型实现为signed integer(通常为 32 或 64 位宽) 代表秒数 自 Unix 时代开始: UTC 时间 1970 年 1 月 1 日午夜(不是 计算闰秒)。一些系统 正确处理负时间值, 而其他人则没有。系统使用 32 位time_t类型易受 Year 2038 problem。
【讨论】:
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。
通常,您会在 bits 或 asm 头目录中找到这些底层实现特定的 gcc 类型定义。对我来说,它是/usr/include/x86_64-linux-gnu/bits/types.h。
您可以只使用 grep 或使用 preprocessor invocation like that suggested by Quassnoi 来查看具体的标题。
【讨论】:
time_t 只是 typedef 8 个字节 (long long/__int64),所有编译器和操作系统都可以理解。过去,它曾经只是用于long int(4 个字节),但现在不是。如果您查看crtdefs.h 中的time_t,您会发现这两种实现方式,但操作系统将使用long long。
【讨论】:
它是大多数旧平台上的 32 位有符号整数类型。但是,这会导致您的代码遭受year 2038 bug 的影响。因此,现代 C 库应该将其定义为有符号的 64 位 int,这在数十亿年内都是安全的。
【讨论】:
[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
【讨论】:
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 中同时看到了typedef __int32_t __time_t; 和typedef __time_t time_t;。你的结果是在 Linux 中明确设置的(至少在 Debian 的 2.6.32-5-xen-amd64 上)。
__time_t 而不是 time_t 来查找 time_t 的底层类型?省略一个步骤?
typedef __time_t time_t;,也需要检查周围的代码以确保实际上使用了 typedef,而不仅仅是条件编译的一部分。 typedef long time_t; 可能也被发现了。
在 Visual Studio 2008 下,它默认为 __int64,除非您定义 _USE_32BIT_TIME_T。你最好假装你不知道它的定义是什么,因为它可以(并且将会)随着平台的变化而变化。
【讨论】: