C++ C/C++;:通过多体系结构支持将时间戳数据读写到文件
从/usr/include/time.h开始:C++ C/C++;:通过多体系结构支持将时间戳数据读写到文件,c++,c,compatibility,32bit-64bit,C++,C,Compatibility,32bit 64bit,从/usr/include/time.h开始: /* Used by other time functions. */ struct tm { int tm_sec;. . . /* Seconds..[0-60] (1 leap second) */ int tm_min;. . . /* Minutes..[0-59] */ int tm_hour;. . . /* Hours.. [0-23] */ int tm_mday;. . . /* Day... [1-31] */ int tm_
/* Used by other time functions. */
struct tm
{
int tm_sec;. . . /* Seconds..[0-60] (1 leap second) */
int tm_min;. . . /* Minutes..[0-59] */
int tm_hour;. . . /* Hours.. [0-23] */
int tm_mday;. . . /* Day... [1-31] */
int tm_mon;. . . /* Month.. [0-11] */
int tm_year;. . . /* Year.- 1900. */
int tm_wday;. . . /* Day of week..[0-6] */
int tm_yday;. . . /* Days in year.[0-365].*/
int tm_isdst;.. . /* DST... [-1/0/1]*/
#ifdef. __USE_BSD
long int tm_gmtoff;. . /* Seconds east of UTC. */
__const char* tm_zone;. / Timezone abbreviation. */
#else
long int __tm_gmtoff;.. /* Seconds east of UTC. */
__const char* __tm_zone;. / Timezone abbreviation. */
#endif
};
如果你想把这个结构写入一个文件,你想让你的程序读回它,并支持多拱(即32位版本写它,64位版本读它),你必须做一些黑客,以确保每个系统的大小相同。有谁知道更好的方法来保持独立于体系结构的时间戳吗?例如,我希望能够将一些结构(例如,time_t或struct tm)写入一个文件,并将其读回任何体系结构。有没有人对此有任何经验或建议?struct tm是在C/C++中存储时间戳的最佳方式吗?我意识到使用这种结构会有相当大的开销
我目前已将结构重新定义为:
//Force 32 bit format and space requirements
struct tm32
{
int tm_sec;. . . /* Seconds..[0-60] (1 leap second) */
int tm_min;. . . /* Minutes..[0-59] */
int tm_hour;. . . /* Hours.. [0-23] */
int tm_mday;. . . /* Day... [1-31] */
int tm_mon;. . . /* Month.. [0-11] */
int tm_year;. . . /* Year.- 1900. */
int tm_wday;. . . /* Day of week..[0-6] */
int tm_yday;. . . /* Days in year.[0-365].*/
int tm_isdst;.. . /* DST... [-1/0/1]*/
int tm_gmtoff; // this does nothing but hold space
int tm_zone; // this does nothing but hold space
};
由于我用来操作struct tm的函数(mktime()、time()、gmtime()、strftime())似乎都没有查看struct tm结构中的最后两个字段,所以我只是在它们的位置上使用整数作为占位符,以便大小始终相同。然而,我仍然在寻找更好的解决方案
编辑:我在上面的修复中使用的int类型可以是int32\u t或选择的任何固定宽度类型 确保文件完全独立于平台的一种方法是使用文本文件
否则,在转换后的结构中包括
,并使用类似uint32\t
的类型。我认为,确保以可在所需平台上读回的方式写入保存的数据不属于“黑客行为”。然而,盲目地以二进制格式保存一个(可能是压缩的)结构,并期望能够轻松地、可移植地读回它,这将是错误的
您需要单独处理每个字段,因为编译器可能会在字段之间添加填充,这些字段将出现在结构的“二进制转储”中,但这完全依赖于编译器,因此对平台之间的互操作性非常不利
我可能会为结构的本机int
字段确定一个合理的精度,比如说32位,然后编写如下内容:
void tm_serialize(FILE *out, const struct tm *tm)
{
int32_serialize(out, tm->tm_sec);
int32_serialize(out, tm->tm_min);
/* and so on */
}
struct tm tm_deserialize(FILE *in)
{
struct tm tm;
tm.tm_sec = int32_deserialize(in);
tm.tm_min = int32_deserialize(in);
/* and so on */
return tm;
}
当然,其中,int32_serialize()
和int32_deserialize()
只需以已知(如big-endian)格式写入(和读取)32位整数的二进制表示,该格式定义明确,易于在任何平台上读取
更新:序列化字符串当然可以采用完全相同的方式,一种流行的格式与C的内存布局相同,即以0结尾的char
数组。那么你就只有:
void string_serialize(FILE *out, const char* string);
int string_deserialize(FILE *in, char *string, size_t max);
在这里,string\u deserialize()
函数必须有缓冲区大小限制,这样它就不会因为读取太多而溢出任何内容。我设想返回值表示成功/失败,因此调用代码可以采取它想要的任何措施
在上面的文章中,我的目标不是最小化空间的序列化,正如一位评论员指出的那样,许多在运行时为int
的字段实际上并不需要那么高的精度,因此可以将它们序列化为更小的字段。如果您想这样做,当然可以发明适当的函数,如int8_serialize()
等,并为每个字段使用正确的函数。struct tm
通常与C/POSIX时间函数一起使用。假设您没有在这些函数允许的范围之外使用它,有两种明显的方法:
- 使用
strftime
写入,使用strptime
读取。优点:非常容易理解以正常时间格式写入的输出数据(例如,使用ISO格式)
- 调用
mktime
将其转换为time\u t
,然后将其写入二进制或ASCII。另一个方向是localtime
或gmtime
。优点:小,二进制通常为4或8字节。对于ASCII,没有大多少
gettimeofday(2)
将返回自历元以来的秒数和微秒数;由于时间的类型为time\u t
,它可能是32位(放置时间的位置)或更大,因此明智的做法是将time\u t
强制转换为uint64\u t
。使用工具以指定的字节顺序存储64位整数。uint32\u t
实际上不会保护您,因为一个体系结构可能是大端,而另一个是小端。或者可能总是有不同的填充。+1-这是序列化结构的通用方法。挑剔:如果要打包,几乎所有这些字段的合适大小都是uint8\u t
tm_year
可能需要更多(甚至是有符号类型),而tm_gmtoff
需要更大和有符号。这解决了存储整数字段的问题,但我仍然需要为char*和long int成员创建标准的固定宽度字段(范围从32位到64位)。在不修改现有数据结构的情况下,使用strftime和strptime听起来是一个不错的解决方案。我看不出我的使用会超出C/POSIX时间函数的预期用途。伊玛,试试看。