[C言語] Windows環境で現在時刻をミリ秒単位で取得する方法

C言語でWindows環境において現在時刻をミリ秒単位で取得するには、GetSystemTimeAsFileTime関数やQueryPerformanceCounter関数を使用する方法があります。

GetSystemTimeAsFileTimeは、システム時刻をファイル時刻形式で取得し、100ナノ秒単位での精度を提供します。

一方、QueryPerformanceCounterは高精度なパフォーマンスカウンタを利用して、より正確な時間計測が可能です。

これらの関数を活用することで、ミリ秒単位での時間取得が実現できます。

この記事でわかること
  • GetTickCount、timeGetTime、QueryPerformanceCounterの利用方法
  • 高精度な時刻取得の実装とその応用例
  • 各関数の精度とパフォーマンスの違い
  • ゲーム開発やデータロギングでの具体的な応用方法

目次から探す

ミリ秒単位での時刻取得

Windows環境で現在時刻をミリ秒単位で取得する方法は、さまざまな関数を利用することで実現できます。

ここでは、代表的な3つの関数について解説します。

GetTickCount関数の利用

GetTickCount関数は、システムが起動してからの経過時間をミリ秒単位で取得するための関数です。

この関数は、システムの起動時間を基準にしているため、現在の時刻を直接取得するものではありませんが、経過時間の計測には便利です。

#include <windows.h>
#include <stdio.h>
int main() {
    // システム起動からの経過時間をミリ秒単位で取得
    DWORD startTime = GetTickCount();
    printf("システム起動からの経過時間: %lu ミリ秒\n", startTime);
    return 0;
}
システム起動からの経過時間: 12345678 ミリ秒

この例では、システムが起動してからの経過時間をミリ秒単位で表示しています。

GetTickCountは、49.7日ごとにリセットされるため、長時間の計測には注意が必要です。

QueryPerformanceCounter関数の利用

QueryPerformanceCounter関数は、高精度なパフォーマンスカウンタの値を取得するための関数です。

この関数は、非常に高い精度で時間を計測することができ、ゲームやリアルタイムアプリケーションでの使用に適しています。

#include <windows.h>
#include <stdio.h>
int main() {
    LARGE_INTEGER frequency, start, end;
    // パフォーマンスカウンタの周波数を取得
    QueryPerformanceFrequency(&frequency);
    // 計測開始時のカウンタ値を取得
    QueryPerformanceCounter(&start);
    // ここで何らかの処理を行う
    // 計測終了時のカウンタ値を取得
    QueryPerformanceCounter(&end);
    // 経過時間をミリ秒単位で計算
    double elapsedTime = (double)(end.QuadPart - start.QuadPart) * 1000.0 / frequency.QuadPart;
    printf("経過時間: %.3f ミリ秒\n", elapsedTime);
    return 0;
}
経過時間: 0.123 ミリ秒

この例では、QueryPerformanceCounterを使用して、処理の経過時間を高精度で計測しています。

QueryPerformanceFrequencyを用いて周波数を取得し、ミリ秒単位での経過時間を計算しています。

timeGetTime関数の利用

timeGetTime関数は、マルチメディアタイマーを使用して、システム起動からの経過時間をミリ秒単位で取得します。

この関数は、GetTickCountと似ていますが、より高い精度を提供することができます。

#include <windows.h>
#include <stdio.h>
#include <mmsystem.h>
#pragma comment(lib, "winmm.lib")
int main() {
    // システム起動からの経過時間をミリ秒単位で取得
    DWORD startTime = timeGetTime();
    printf("システム起動からの経過時間: %lu ミリ秒\n", startTime);
    return 0;
}
システム起動からの経過時間: 12345678 ミリ秒

この例では、timeGetTimeを使用して、システム起動からの経過時間をミリ秒単位で取得しています。

timeGetTimeは、GetTickCountよりも高い精度を持ち、マルチメディアアプリケーションでの使用に適しています。

高精度な時刻取得の実装

高精度な時刻取得は、特にリアルタイム性が求められるアプリケーションにおいて重要です。

ここでは、QueryPerformanceFrequency関数を用いた高精度な時刻取得の方法と、その実装例について解説します。

QueryPerformanceFrequency関数の理解

QueryPerformanceFrequency関数は、パフォーマンスカウンタの周波数を取得するための関数です。

この周波数は、QueryPerformanceCounter関数で取得したカウンタ値を時間に変換するために使用されます。

周波数は、カウンタが1秒間に何回カウントするかを示しており、通常は非常に高い値を持ちます。

#include <windows.h>
#include <stdio.h>
int main() {
    LARGE_INTEGER frequency;
    // パフォーマンスカウンタの周波数を取得
    if (QueryPerformanceFrequency(&frequency)) {
        printf("パフォーマンスカウンタの周波数: %lld\n", frequency.QuadPart);
    } else {
        printf("パフォーマンスカウンタの取得に失敗しました。\n");
    }
    return 0;
}

このコードは、パフォーマンスカウンタの周波数を取得し、表示します。

周波数が高いほど、より高精度な時間計測が可能です。

高精度タイマーの実装例

高精度タイマーを実装することで、非常に短い時間間隔の計測が可能になります。

以下の例では、QueryPerformanceCounterQueryPerformanceFrequencyを組み合わせて、処理の経過時間を高精度で計測します。

#include <windows.h>
#include <stdio.h>
void highPrecisionTask() {
    // ここに高精度で計測したい処理を記述
    for (volatile int i = 0; i < 1000000; i++); // ダミー処理
}
int main() {
    LARGE_INTEGER frequency, start, end;
    // パフォーマンスカウンタの周波数を取得
    QueryPerformanceFrequency(&frequency);
    // 計測開始時のカウンタ値を取得
    QueryPerformanceCounter(&start);
    highPrecisionTask(); // 高精度で計測したい処理を呼び出し
    // 計測終了時のカウンタ値を取得
    QueryPerformanceCounter(&end);
    // 経過時間をミリ秒単位で計算
    double elapsedTime = (double)(end.QuadPart - start.QuadPart) * 1000.0 / frequency.QuadPart;
    printf("高精度処理の経過時間: %.3f ミリ秒\n", elapsedTime);
    return 0;
}
高精度処理の経過時間: 12.345 ミリ秒

この例では、highPrecisionTask関数内の処理を高精度で計測しています。

QueryPerformanceCounterを用いることで、非常に短い時間間隔でも正確に計測することができます。

精度とパフォーマンスのトレードオフ

高精度な時刻取得は非常に便利ですが、常に最適な選択とは限りません。

以下の表は、精度とパフォーマンスのトレードオフを示しています。

スクロールできます
関数名精度パフォーマンス
GetTickCount高速
timeGetTime中速
QueryPerformanceCounter低速(高精度)
  • GetTickCount: 精度は低いが、非常に高速で、システム起動からの経過時間を取得するのに適しています。
  • timeGetTime: 中程度の精度とパフォーマンスを持ち、マルチメディアアプリケーションでの使用に適しています。
  • QueryPerformanceCounter: 非常に高い精度を持ちますが、パフォーマンスは低下します。

リアルタイム性が求められるアプリケーションでの使用に適しています。

高精度が必要な場合はQueryPerformanceCounterを使用し、パフォーマンスが重要な場合はGetTickCounttimeGetTimeを選択するのが良いでしょう。

応用例

高精度な時刻取得は、さまざまな分野で応用されています。

ここでは、具体的な応用例として、ゲーム開発、データロギングシステム、リアルタイムシステムでの利用方法を紹介します。

ゲーム開発におけるフレームレート制御

ゲーム開発では、フレームレートを一定に保つことが重要です。

フレームレートが不安定だと、ゲームの動作が滑らかでなくなり、プレイヤーの体験に影響を与えます。

QueryPerformanceCounterを使用することで、フレームごとの経過時間を高精度で計測し、フレームレートを制御することができます。

#include <windows.h>
#include <stdio.h>
void renderFrame() {
    // フレームの描画処理を記述
}
int main() {
    LARGE_INTEGER frequency, start, end;
    QueryPerformanceFrequency(&frequency);
    double targetFrameTime = 1000.0 / 60.0; // 60 FPSを目指す
    while (1) {
        QueryPerformanceCounter(&start);
        renderFrame(); // フレームの描画
        QueryPerformanceCounter(&end);
        double elapsedTime = (double)(end.QuadPart - start.QuadPart) * 1000.0 / frequency.QuadPart;
        // フレームレートを制御するための待機
        if (elapsedTime < targetFrameTime) {
            Sleep((DWORD)(targetFrameTime - elapsedTime));
        }
    }
    return 0;
}

この例では、60 FPSを目指してフレームレートを制御しています。

QueryPerformanceCounterを用いてフレームごとの経過時間を計測し、必要に応じてSleep関数で待機時間を調整しています。

データロギングシステムでのタイムスタンプ

データロギングシステムでは、データの正確なタイムスタンプが求められます。

QueryPerformanceCounterを使用することで、データが記録された正確な時刻をミリ秒単位で取得し、タイムスタンプとして記録することができます。

#include <windows.h>
#include <stdio.h>
void logData(const char* data) {
    LARGE_INTEGER frequency, counter;
    QueryPerformanceFrequency(&frequency);
    QueryPerformanceCounter(&counter);
    double timestamp = (double)counter.QuadPart * 1000.0 / frequency.QuadPart;
    printf("データ: %s, タイムスタンプ: %.3f ミリ秒\n", data, timestamp);
}
int main() {
    logData("センサーデータ1");
    logData("センサーデータ2");
    return 0;
}

この例では、データに対して高精度なタイムスタンプを付与しています。

QueryPerformanceCounterを用いることで、データが記録された正確な時刻を取得し、ログに出力しています。

リアルタイムシステムでのイベントタイミング

リアルタイムシステムでは、イベントのタイミングが非常に重要です。

QueryPerformanceCounterを使用することで、イベントの発生タイミングを高精度で計測し、システムの応答性を向上させることができます。

#include <windows.h>
#include <stdio.h>
void handleEvent() {
    // イベント処理を記述
}
int main() {
    LARGE_INTEGER frequency, start, end;
    QueryPerformanceFrequency(&frequency);
    while (1) {
        // イベントが発生したと仮定
        QueryPerformanceCounter(&start);
        handleEvent(); // イベントの処理
        QueryPerformanceCounter(&end);
        double eventTime = (double)(end.QuadPart - start.QuadPart) * 1000.0 / frequency.QuadPart;
        printf("イベント処理時間: %.3f ミリ秒\n", eventTime);
    }
    return 0;
}

この例では、イベント処理の時間を高精度で計測しています。

QueryPerformanceCounterを用いることで、イベントの発生から処理完了までの時間を正確に計測し、システムの応答性を確認することができます。

よくある質問

GetTickCount関数はどのくらいの精度がありますか?

GetTickCount関数は、システム起動からの経過時間をミリ秒単位で取得しますが、その精度は約15ミリ秒程度です。

このため、非常に短い時間間隔の計測には向いていません。

精度が必要な場合は、QueryPerformanceCounterを使用することをお勧めします。

QueryPerformanceCounterはすべてのWindows環境で利用可能ですか?

QueryPerformanceCounterは、ほとんどの現代的なWindows環境で利用可能です。

ただし、非常に古いハードウェアや特定の設定では、サポートされていない場合があります。

QueryPerformanceFrequencyを使用して、パフォーマンスカウンタが利用可能かどうかを確認することが重要です。

ミリ秒単位の精度が必要ない場合、どの関数を使うべきですか?

ミリ秒単位の精度が必要ない場合は、GetTickCounttimeGetTimeを使用することが適しています。

これらの関数は、システム起動からの経過時間を取得するのに十分な精度を持ち、パフォーマンスも良好です。

特に、GetTickCountは非常に高速で、一般的な用途に適しています。

まとめ

Windows環境での時刻取得には、用途に応じたさまざまな関数が用意されています。

GetTickCounttimeGetTimeQueryPerformanceCounterの各関数は、それぞれ異なる精度とパフォーマンス特性を持ち、適切な選択が重要です。

この記事を通じて、あなたのアプリケーションに最適な時刻取得方法を見つけ、実装に役立ててください。

当サイトはリンクフリーです。出典元を明記していただければ、ご自由に引用していただいて構いません。

関連カテゴリーから探す

  • URLをコピーしました!
目次から探す