2

我想在 windows 和 linux 中使用以下函数,但我不确定如何将 __int64 转换为 unsigned long。像我一样投射价值是否安全?

getTimeInMilliseconds()
{
    #ifdef _WIN32


        static const __int64 magic = 116444736000000000; // 1970/1/1
        SYSTEMTIME st;
        GetSystemTime(&st);
        FILETIME   ft;
        SystemTimeToFileTime(&st,&ft); // in 100-nanosecs...
        __int64 t;
        memcpy(&t,&ft,sizeof t);
        return (unsigned long)((t - magic)/10000);
    #else
        struct timeval tv;
        gettimeofday(&tv, NULL);
        unsigned long s = tv.tv_sec * 1000;
        unsigned long us = tv.tv_usec / 1000;
        return s + us;
    #endif
}
4

1 回答 1

1

是的,它是“安全的”,从语法上讲,您可以执行代码中所写的内容。当将 64 位 int 降级为 32 位长 int 时,您自然会丢失前 32 位,如果您的值足够小,这不是问题,问题是您的值实际上不够小。

两种定义(WIN32 和非 WIN32)都存在溢出问题,不是因为您不能将 64 位 int 转换为 long,而是因为您试图将太大的值塞进太小的容器中。

问题#1,函数名称将结果描述为“以毫秒为单位的时间”,这是错误的,两种实现都试图以微秒(千秒)而不是“毫秒”(百万分之一秒)为单位返回结果。确定你真正想要的结果并适当地标记它,从长远来看减少混乱。请注意,100 纳秒(十亿分之一秒)的间隔与 1/10 毫秒相同,也就是 1/10,000 微秒,仅供参考。

问题 #2:将 FILETIME 结构转换为 long int 的“memcpy”也是错误的。FILETIME 和 __int64 有不同的字节对齐方式,这样你就会把这些位放在错误的地方。要将 FILETIME 转换为 _int64,您需要执行以下操作:

LARGE_INTEGER foo;
FILETIME baz;
__int64 bar;

foo.HighPart = baz.dwHighDateTime;
foo.LowPart = baz.dwLowDateTime;
bar = foo.Quadpart;

问题#3:一个 32 位长的 int 只能存储足够大的时间值,以秒为单位使用,即使这样也只能到 2038 年初,这就是为什么“timeval”有一个单独的成员来表示“微秒”它不仅仅是让你的生活变得艰难。

如果您希望在单个值中达到数千秒,则至少需要 36 位(可能更像 38-40)才能拥有可以引用比 1970-2038 更稳健时间范围内的值的时间。由于很少有编译器支持 40 位整数,我建议只升级到完整的 64 位,除非由于某种原因你不能在这种情况下,你应该为你正在尝试做的事情想出一个更好的解决方案大约。

于 2012-07-18T19:17:43.847 回答