2

WindowsとLinuxで次の関数を使用したいのですが、__int64をunsignedlongに変換する方法がわかりません。私のように値をキャストしても安全ですか?

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 ビット long int にダウングレードすると、上位 32 ビットが自然に失われます。これは、値が十分に小さければ問題ではありません。問題は、値が実際には十分に小さくないことです。

両方の定義 (WIN32 とそれ以外) は、64 ビットの int を long にキャストできないためではなく、大きすぎる値を小さすぎるコンテナーに詰め込もうとしているために、オーバーフローの問題が発生する可能性があります。

問題#1、関数名は結果を「ミリ秒単位の時間」と表現していますが、これは偽です。両方の実装は、100万分の1秒である「ミリ秒」ではなく、マイクロ秒(数千秒)で結果を返そうとしています。実際に狙っている結果を決定し、適切にラベルを付けて、長期的には混乱を減らします。100 ナノ秒 (10 億分の 1 秒) の間隔は、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 年の初めまでしか保存できません。あなたの人生を難しくする。

単一の値で数千秒が必要な場合は、少なくとも 36 ビット、おそらく 38 ~ 40 ビットが必要で、1970 ~ 2038 年よりも堅牢な時間枠の値を参照できる時間が必要です。40 ビット整数をサポートしているコンパイラはほとんどないため、完全な 64 ビットにアップグレードすることをお勧めします。その周り。

于 2012-07-18T19:17:43.847 に答える