【C言語】現在時刻をミリ秒単位で取得する方法

この記事では、初心者の方でも理解しやすいように、gettimeofday()関数を使った時刻取得方法や、WindowsとPOSIX環境での具体的な実装方法を解説します。

また、時間計測の応用例やタイマー機能の実装方法についても紹介します。

さらに、精度とパフォーマンスのバランスを取るためのベストプラクティスや、クロスプラットフォーム対応の注意点についても触れています。

目次から探す

ミリ秒単位での時刻取得

C言語で現在時刻をミリ秒単位で取得する方法について解説します。

ミリ秒単位の時刻取得は、精度の高い時間計測やタイミング制御が必要なアプリケーションで非常に重要です。

ここでは、gettimeofday()関数を中心に、Windows環境とPOSIX環境での時刻取得方法についても説明します。

gettimeofday()関数を使ったミリ秒単位の時刻取得

gettimeofday()関数は、POSIX標準の関数で、現在の時刻を秒とマイクロ秒単位で取得することができます。

この関数は、以下のように使用します。

#include <sys/time.h>
#include <stdio.h>
int main() {
    struct timeval tv;
    gettimeofday(&tv, NULL);
    printf("秒: %ld\n", tv.tv_sec);
    printf("マイクロ秒: %ld\n", tv.tv_usec);
    return 0;
}

このコードを実行すると、現在の時刻が秒とマイクロ秒単位で表示されます。

struct timevalのtv_secとtv_usecの使い方

struct timevalは、gettimeofday()関数で使用される構造体で、以下の2つのメンバを持ちます。

  • tv_sec: 現在の時刻を秒単位で表す
  • tv_usec: 現在の時刻をマイクロ秒単位で表す

これらのメンバを使って、現在の時刻をミリ秒単位に変換することができます。

ミリ秒に変換する方法

gettimeofday()関数で取得した時刻をミリ秒単位に変換するには、以下のようにします。

#include <sys/time.h>
#include <stdio.h>
int main() {
    struct timeval tv;
    gettimeofday(&tv, NULL);
    long milliseconds = tv.tv_sec * 1000 + tv.tv_usec / 1000;
    printf("ミリ秒: %ld\n", milliseconds);
    return 0;
}

このコードでは、秒をミリ秒に変換し、マイクロ秒をミリ秒に変換して加算しています。

クロスプラットフォームでの対応

C言語での時刻取得は、プラットフォームによって異なる方法が必要です。

POSIX環境ではgettimeofday()関数が使用できますが、Windows環境では異なる関数を使用する必要があります。

Windows環境での時刻取得方法

Windows環境では、GetSystemTimeAsFileTime()関数を使用して現在の時刻を取得し、それをミリ秒単位に変換することができます。

以下はその例です。

#include <windows.h>
#include <stdio.h>
int main() {
    FILETIME ft;
    GetSystemTimeAsFileTime(&ft);
    ULARGE_INTEGER uli;
    uli.LowPart = ft.dwLowDateTime;
    uli.HighPart = ft.dwHighDateTime;
    // 100ナノ秒単位をミリ秒に変換
    long milliseconds = (long)(uli.QuadPart / 10000);
    printf("ミリ秒: %ld\n", milliseconds);
    return 0;
}

このコードでは、GetSystemTimeAsFileTime()関数で取得した時刻をULARGE_INTEGER型に変換し、100ナノ秒単位をミリ秒に変換しています。

POSIX環境での時刻取得方法

POSIX環境では、前述の通りgettimeofday()関数を使用します。

以下に再度例を示します。

#include <sys/time.h>
#include <stdio.h>
int main() {
    struct timeval tv;
    gettimeofday(&tv, NULL);
    long milliseconds = tv.tv_sec * 1000 + tv.tv_usec / 1000;
    printf("ミリ秒: %ld\n", milliseconds);
    return 0;
}

このように、POSIX環境ではgettimeofday()関数を使って簡単にミリ秒単位の時刻を取得することができます。

以上が、C言語で現在時刻をミリ秒単位で取得する方法です。

プラットフォームに応じた適切な方法を選択し、精度の高い時間計測を行いましょう。

応用例

時間計測の応用

C言語でミリ秒単位の時刻を取得する方法を学んだら、次にその応用例を見ていきましょう。

時間計測はプログラムのパフォーマンスを評価するために非常に重要です。

以下では、具体的な応用例として処理時間の計測方法、ベンチマークテストの実施例、タイマー機能の実装方法について解説します。

処理時間の計測方法

処理時間の計測は、特定のコードブロックがどれだけの時間を要するかを知るために行います。

以下に、gettimeofday()関数を使って処理時間を計測する方法を示します。

#include <stdio.h>
#include <sys/time.h>
void some_function() {
    // 計測したい処理
    for (int i = 0; i < 1000000; i++);
}
int main() {
    struct timeval start, end;
    long mtime, seconds, useconds;
    // 開始時刻を取得
    gettimeofday(&start, NULL);
    // 計測対象の関数を呼び出し
    some_function();
    // 終了時刻を取得
    gettimeofday(&end, NULL);
    // 経過時間を計算
    seconds  = end.tv_sec  - start.tv_sec;
    useconds = end.tv_usec - start.tv_usec;
    mtime = ((seconds) * 1000 + useconds/1000.0) + 0.5;
    printf("Elapsed time: %ld milliseconds\n", mtime);
    return 0;
}

このプログラムでは、some_function()の実行時間をミリ秒単位で計測しています。

ベンチマークテストの実施例

ベンチマークテストは、プログラムやアルゴリズムの性能を評価するために行います。

以下に、簡単なベンチマークテストの例を示します。

#include <stdio.h>
#include <sys/time.h>
void function_to_benchmark() {
    // ベンチマーク対象の処理
    for (int i = 0; i < 1000000; i++);
}
int main() {
    struct timeval start, end;
    long mtime, seconds, useconds;
    // 開始時刻を取得
    gettimeofday(&start, NULL);
    // ベンチマーク対象の関数を呼び出し
    function_to_benchmark();
    // 終了時刻を取得
    gettimeofday(&end, NULL);
    // 経過時間を計算
    seconds  = end.tv_sec  - start.tv_sec;
    useconds = end.tv_usec - start.tv_usec;
    mtime = ((seconds) * 1000 + useconds/1000.0) + 0.5;
    printf("Benchmark time: %ld milliseconds\n", mtime);
    return 0;
}

このプログラムでは、function_to_benchmark()の実行時間を計測し、ベンチマーク結果として表示します。

タイマー機能の実装

タイマー機能は、一定の時間間隔で特定の処理を実行するために使用されます。

以下に、簡単なタイマー機能の実装例を示します。

#include <stdio.h>
#include <sys/time.h>
#include <unistd.h>
void timer_function() {
    printf("Timer triggered!\n");
}
int main() {
    struct timeval start, end;
    long mtime, seconds, useconds;
    int interval = 1000; // タイマー間隔(ミリ秒)
    // 開始時刻を取得
    gettimeofday(&start, NULL);
    while (1) {
        // 現在時刻を取得
        gettimeofday(&end, NULL);
        // 経過時間を計算
        seconds  = end.tv_sec  - start.tv_sec;
        useconds = end.tv_usec - start.tv_usec;
        mtime = ((seconds) * 1000 + useconds/1000.0) + 0.5;
        // タイマー間隔が経過したか確認
        if (mtime >= interval) {
            timer_function();
            // 開始時刻を更新
            gettimeofday(&start, NULL);
        }
        // CPU負荷を軽減するために少し待機
        usleep(1000);
    }
    return 0;
}

このプログラムでは、1秒ごとにtimer_function()が呼び出されます。

簡易タイマーの作成方法

簡易タイマーを作成する方法を以下に示します。

このタイマーは、指定した時間が経過したらメッセージを表示します。

#include <stdio.h>
#include <sys/time.h>
#include <unistd.h>
void simple_timer(int duration) {
    struct timeval start, end;
    long mtime, seconds, useconds;
    // 開始時刻を取得
    gettimeofday(&start, NULL);
    while (1) {
        // 現在時刻を取得
        gettimeofday(&end, NULL);
        // 経過時間を計算
        seconds  = end.tv_sec  - start.tv_sec;
        useconds = end.tv_usec - start.tv_usec;
        mtime = ((seconds) * 1000 + useconds/1000.0) + 0.5;
        // 指定時間が経過したか確認
        if (mtime >= duration) {
            printf("Timer finished: %d milliseconds elapsed\n", duration);
            break;
        }
        // CPU負荷を軽減するために少し待機
        usleep(1000);
    }
}
int main() {
    int duration = 5000; // タイマー時間(ミリ秒)
    simple_timer(duration);
    return 0;
}

このプログラムでは、5秒後に Timer finished: 5000 milliseconds elapsed というメッセージが表示されます。

タイマーを使ったアプリケーション例

タイマー機能を使ったアプリケーションの例として、簡単なストップウォッチを作成してみましょう。

#include <stdio.h>
#include <sys/time.h>
#include <unistd.h>
void start_stopwatch() {
    struct timeval start, end;
    long mtime, seconds, useconds;
    // 開始時刻を取得
    gettimeofday(&start, NULL);
    printf("Press Enter to stop the stopwatch...\n");
    getchar(); // Enterキーが押されるまで待機
    // 終了時刻を取得
    gettimeofday(&end, NULL);
    // 経過時間を計算
    seconds  = end.tv_sec  - start.tv_sec;
    useconds = end.tv_usec - start.tv_usec;
    mtime = ((seconds) * 1000 + useconds/1000.0) + 0.5;
    printf("Elapsed time: %ld milliseconds\n", mtime);
}
int main() {
    start_stopwatch();
    return 0;
}

このプログラムでは、Enterキーが押されるまでの時間を計測し、ミリ秒単位で表示します。

これにより、簡単なストップウォッチ機能を実現できます。

以上が、C言語でミリ秒単位の時刻取得を応用した具体例です。

これらの例を参考にして、さらに高度な時間計測やタイマー機能を実装してみてください。

注意点とベストプラクティス

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

C言語で現在時刻をミリ秒単位で取得する際には、精度とパフォーマンスのトレードオフを考慮する必要があります。

高精度な時間計測は、システムリソースを多く消費する可能性があります。

例えば、gettimeofday()関数は比較的高精度ですが、頻繁に呼び出すとパフォーマンスに影響を与えることがあります。

高精度な時間計測のコスト

高精度な時間計測を行うためには、システムコールを頻繁に使用する必要があります。

これにより、CPUの負荷が増加し、他のプロセスの実行に影響を与える可能性があります。

特にリアルタイム性が求められるアプリケーションでは、適切なバランスを見つけることが重要です。

適切な精度の選び方

アプリケーションの要件に応じて、適切な精度を選ぶことが重要です。

例えば、ユーザーインターフェースの更新やログの記録にはミリ秒単位の精度が必要ですが、システム全体のパフォーマンスを考慮して、必要以上の精度を求めないようにすることが重要です。

クロスプラットフォーム対応の注意点

C言語での時間計測は、使用するプラットフォームによって異なるAPIを使用する必要があります。

例えば、WindowsではGetSystemTimeAsFileTime()QueryPerformanceCounter()を使用し、POSIX準拠のシステムではgettimeofday()clock_gettime()を使用します。

クロスプラットフォーム対応を考慮する場合、条件付きコンパイルを使用して、適切なAPIを選択することが重要です。

異なるOS間での互換性

異なるOS間での互換性を保つためには、抽象化レイヤーを設けることが有効です。

例えば、時間計測のための関数を独自に定義し、その中でプラットフォームごとのAPIを呼び出すようにすることで、コードの可読性と保守性を向上させることができます。

プラットフォーム依存コードの管理方法

プラットフォーム依存のコードを管理するためには、以下のような方法があります:

  1. 条件付きコンパイル: #ifdef#ifndefを使用して、プラットフォームごとに異なるコードをコンパイルする。
  2. 抽象化レイヤー: プラットフォームごとの実装を隠蔽するための抽象化レイヤーを設ける。
  3. ビルドシステムの活用: CMakeやMakefileを使用して、プラットフォームごとのビルド設定を管理する。

以下は、条件付きコンパイルを使用した例です:

#include <stdio.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <sys/time.h>
#endif
void get_current_time_in_milliseconds() {
#ifdef _WIN32
    FILETIME ft;
    GetSystemTimeAsFileTime(&ft);
    // Windowsの時刻取得処理
#else
    struct timeval tv;
    gettimeofday(&tv, NULL);
    // POSIXの時刻取得処理
#endif
}
int main() {
    get_current_time_in_milliseconds();
    return 0;
}

このようにすることで、プラットフォームごとの違いを吸収し、コードの可読性と保守性を向上させることができます。

目次から探す