5

Windows は Windows Vista までは GetTickCount のみを提供し、その OS から GetTickCount64 も提供します。さまざまな関数の呼び出しを使用してCプログラムをコンパイルするにはどうすればよいですか?

インクルードされたヘッダー ファイルで関数が宣言されているかどうかをCコンパイラでチェックし、特定の関数が使用可能かどうかに応じてコードのさまざまな部分をコンパイルするにはどうすればよいですか?

#if ??????????????????????????????
unsigned long long get_tick_count(void) { return GetTickCount64(); }
#else
unsigned long long get_tick_count(void) { return GetTickCount(); }
#endif

ヒントだけでなく、実際に動作するサンプル ファイルを探しています。

編集:(64ビット)Windows 7 RCでMinGWのgcc 3.4.5を使用して次のことを試しましたが、役に立ちませんでした。これが MinGW の問題である場合、この問題を回避するにはどうすればよいですか?

#include <windows.h>
#if (WINVER >= 0x0600)
unsigned long long get_tick_count(void) { return 600/*GetTickCount64()*/; }
#else
unsigned long long get_tick_count(void) { return 0/*GetTickCount()*/; }
#endif
4

10 に答える 10

4

これは、Windowsヘッダーのプリプロセッサ定義を使用して実現できます。

unsigned long long
get_tick_count(void)
{
#if WINVER >= 0x0600
    return GetTickCount64();
#else
    return GetTickCount();
#endif
}
于 2009-06-18T13:11:12.397 に答える
2

この種の問題に対処する正しい方法は、関数が使用可能かどうかを確認することですが、プロジェクトのコンパイル中にこれを確実に行うことはできません。構成段階を追加する必要があります。詳細はビルドツールによって異なります。cmakeとsconsの両方、2つのクロスプラットフォームビルドツールが機能を提供します。基本的に、次のようになります。

/* config.h */
#define HAVE_GETTICKSCOUNT64_FUNC

そして、あなたのプロジェクトでは、次のことを行います。

#include "config.h"

#ifdef HAVE_GETTICKSCOUNT64_FUNC
....
#else
...
#endif

明らかな方法に似ていますが、長期的にははるかに保守しやすくなっています。特に、バージョンに依存することはできるだけ避け、代わりに機能を確認する必要があります。バージョンをチェックすると、複雑なインターリーブされた条件がすぐに発生しますが、上記の手法では、すべてが1つのconfig.hから制御され、できれば自動的に生成されます。

sconsとcmakeでは、関数が使用可能かどうかをチェックするために自動的に実行されるテストがあり、チェックに応じてconfig.hで変数を定義します。基本的な考え方は、機能の検出/設定をコードから切り離すことです

これは、異なるプラットフォームで実行されるバイナリをビルドする必要がある場合を処理できることに注意してください(たとえば、Vistaでビルドされている場合でもXPで実行されます)。config.hを変更するだけです。うまくやれば、それはconfig.hを変更するだけの問題です(任意のプラットフォームでconfig.hを生成し、Windows XP、Vistaなどのconfig.hを収集するスクリプトを作成できます)。UNIXに固有のものではないと思います。

于 2009-06-18T13:30:40.830 に答える
1

あなたはCについて質問していますが、質問にはC++のタグも付けられています...

C ++では、SFINAE手法を使用します。同様の質問を参照してください。

関数の存在を確認するためのテンプレートを作成することは可能ですか?

ただし、提供されている場合は、Windowsでプリプロセッサディレクティブを使用してください。

于 2009-06-18T13:12:25.047 に答える
1

コードがVistaより前のOSで実行される場合、GetTickCount64()はXPマシンに存在しないため、呼び出しをGetTickCount64()にコンパイルすることはできません。

実行時に実行しているオペレーティングシステムを特定してから、正しい関数を呼び出す必要があります。一般に、両方の呼び出しがコードに含まれている必要があります。

Vista +マシンではGetTickCount64()を、XP-マシンではGetTickCount()を呼び出す必要がない場合は、これが当てはまらない可能性があります。実行しているOSに関係なく、GetTickCount()を呼び出すことができる場合があります。ドキュメントには、APIからGetTickCount()を削除していることがわかりました。

また、GetTickCount()を使用するのは適切ではない可能性があることも指摘しておきます。ドキュメントには、ミリ秒数が返されると書かれていますが、実際には、関数の精度は1ミリ秒にも近くありません。マシンによっては(そして実行時にAFAIKを知る方法がない場合)、精度は40ミリ秒以上になる可能性があります。1ミリ秒の精度が必要な場合は、QueryPerformanceCounter()を使用する必要があります。実際、GetTickCount()を使用するすべての場合に、QPCを使用しないという実際的な理由はありません。

于 2009-06-18T14:45:47.980 に答える
1

以前の回答は、特定のケースに存在する特定の #define をチェックすることを指摘していました。この回答は、関数が使用可能かどうかにかかわらず、さまざまなコードをコンパイルするより一般的なケースに対するものです。

C ファイル自体ですべてを実行しようとするのではなく、configure スクリプトが真価を発揮するのは、このようなことです。Linux で実行している場合は、ためらうことなくGNU Autotoolsを紹介します。少なくとも Cygwin または MSYS を使用している場合は、Windows で使用できるポートがあることは知っていますが、それらがどれほど効果的かはわかりません。

sh が手元にある場合に機能する単純な (そして非常に醜い) スクリプト (これをテストするのに便利な Windows セットアップがありません) は、次のようになります。

#!/bin/sh

# First, create a .c file that tests for the existance of GetTickCount64()

cat >conftest.c <<_CONFEOF
#include <windows.h>
int main() {
    GetTickCount64();
    return 0;
}
_CONFEOF

# Then, try to actually compile the above .c file

gcc conftest.c -o conftest.out

# Check gcc's return value to determine if it worked.
#   If it returns 0, compilation worked so set CONF_HASGETTICKCOUNT64
#   If it doesn't return 0, there was an error, so probably no GetTickCount64()

if [ $? -eq 0 ]
then
    confdefs='-D CONF_HASGETTICKCOUNT64=1'
fi

# Now get rid of the temporary files we made.

rm conftest.c
rm conftest.out

# And compile your real program, passing CONF_HASGETTICKCOUNT64 if it exists.

gcc $confdefs yourfile.c

これは、選択したスクリプト言語に簡単に変換できるはずです。プログラムに追加のインクルード パスやコンパイラ フラグなどが必要な場合は、必要なフラグをテスト コンパイルと実際のコンパイルの両方に必ず追加してください。

「yourfile.c」は次のようになります。

#include <windows.h>

unsigned long long get_tick_count(void) {
#ifdef CONF_HASGETTICKCOUNT64
  return GetTickCount64();
#else
  return GetTickCount();
#endif
}
于 2009-06-18T14:17:50.703 に答える
1

こんばんは

探す必要があるのは NTDDI_VERSION ではありませんか?

更新: WINVER が 0x0600 かどうかを確認します。その場合は、Vista を実行しています。

編集:セマンティック ペッカー ヘッドについては、Vista 環境でコンパイラを実行することを意味していました。質問はコンパイルのみを指し、質問はコンパイル時にのみ使用されるヘッダーファイルのみを指します。ほとんどの人は、Vista 環境でコンパイルすることが意図されていることを理解していました。この質問は、実行時の動作には言及していません。

誰かが Vista を実行していて、Windows XP 用にコンパイルしている場合を除きますか?

おい!

HTH

乾杯、

于 2009-06-18T13:09:01.013 に答える
0

たぶんそれはGetTickCount()の良い代替品です

double __stdcall
thetimer (int value)
{
    static double freq = 0;
    static LARGE_INTEGER first;
    static LARGE_INTEGER second;

    if (0 == value)
        {
            if (freq == 0)
            {
                QueryPerformanceFrequency (&first);
                freq = (double) first.QuadPart;
            }
            QueryPerformanceCounter (&first);
            return 0;
        }
    if (1 == value)
        {
            QueryPerformanceCounter (&second);
            second.QuadPart = second.QuadPart - first.QuadPart;
            return (double) second.QuadPart / freq;
        }
    return 0;
}
于 2009-10-25T17:01:43.423 に答える
0

Vista より前のバージョンをサポートする必要がある場合は、GetTickCount() のみを使用することに固執します。それ以外の場合は、ランタイム コードを実装して Windows のバージョンを確認し、Windows の Vista 以前のバージョンでは GetTickCount() を呼び出し、Vista 以降では GetTickCount64() を呼び出す必要があります。これらは異なるサイズの値 (ULONGLONG と DWORD) を返すため、返される値を個別に処理する必要もあります。GetTickCount() のみを使用 (およびオーバーフローのチェック) すると、両方の状況で機能しますが、使用可能な場合に GetTickCount64() を使用すると、コードが複雑になり、記述するコードの量が 2 倍になります。

アプリを Vista より前のマシンで実行する必要がなくなったことを確認できるまで、GetTickCount() のみを使用してください。

于 2009-06-18T19:13:35.310 に答える
0

Microsoft コンパイラは、64 ビット マシン用にコンパイルするときに _WIN64 を定義します。

http://msdn.microsoft.com/en-us/library/b0084kay%28VS.80%29.aspx

#if defined(_WIN64)
unsigned long long get_tick_count(void) { return GetTickCount64(); }
#else
unsigned long long get_tick_count(void) { return GetTickCount(); }
#endif
于 2009-06-18T13:10:56.983 に答える