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;
}
このコードは、パフォーマンスカウンタの周波数を取得し、表示します。
周波数が高いほど、より高精度な時間計測が可能です。
高精度タイマーの実装例
高精度タイマーを実装することで、非常に短い時間間隔の計測が可能になります。
以下の例では、QueryPerformanceCounter
とQueryPerformanceFrequency
を組み合わせて、処理の経過時間を高精度で計測します。
#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
を使用し、パフォーマンスが重要な場合はGetTickCount
やtimeGetTime
を選択するのが良いでしょう。
応用例
高精度な時刻取得は、さまざまな分野で応用されています。
ここでは、具体的な応用例として、ゲーム開発、データロギングシステム、リアルタイムシステムでの利用方法を紹介します。
ゲーム開発におけるフレームレート制御
ゲーム開発では、フレームレートを一定に保つことが重要です。
フレームレートが不安定だと、ゲームの動作が滑らかでなくなり、プレイヤーの体験に影響を与えます。
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
を用いることで、イベントの発生から処理完了までの時間を正確に計測し、システムの応答性を確認することができます。
よくある質問
まとめ
Windows環境での時刻取得には、用途に応じたさまざまな関数が用意されています。
GetTickCount
、timeGetTime
、QueryPerformanceCounter
の各関数は、それぞれ異なる精度とパフォーマンス特性を持ち、適切な選択が重要です。
この記事を通じて、あなたのアプリケーションに最適な時刻取得方法を見つけ、実装に役立ててください。