残念ながら、クロスプラットフォーム、クロスコンパイラ環境では、純粋にコンパイル時にこれを実行する単一の信頼できる方法はありません。
- プロジェクトの設定に欠陥があるか破損している場合(特にVisual Studio 2008 SP1の場合)、_ WIN32と_WIN64の両方が未定義になることがあります。
- 「Win32」というラベルの付いたプロジェクトは、プロジェクト構成エラーのため、64ビットに設定されている可能性があります。
- 現在の#defineによると、Visual Studio 2008 SP1では、インテリセンスがコードの正しい部分をグレー表示しない場合があります。これにより、コンパイル時に使用されている#defineを正確に確認することが難しくなります。
したがって、唯一の信頼できる方法は、3つの単純なチェックを組み合わせることです。
- 1)コンパイル時間設定、および;
- 2)ランタイムチェック、および;
- 3)堅牢なコンパイル時間チェック。
簡単なチェック1/3:コンパイル時間設定
必要な#define変数を設定する方法を選択します。@JaredParのメソッドをお勧めします。
// Check windows
#if _WIN32 || _WIN64
#if _WIN64
#define ENV64BIT
#else
#define ENV32BIT
#endif
#endif
// Check GCC
#if __GNUC__
#if __x86_64__ || __ppc64__
#define ENV64BIT
#else
#define ENV32BIT
#endif
#endif
シンプルチェック2/3:ランタイムチェック
main()で、sizeof()が意味があるかどうかをダブルチェックします。
#if defined(ENV64BIT)
if (sizeof(void*) != 8)
{
wprintf(L"ENV64BIT: Error: pointer should be 8 bytes. Exiting.");
exit(0);
}
wprintf(L"Diagnostics: we are running in 64-bit mode.\n");
#elif defined (ENV32BIT)
if (sizeof(void*) != 4)
{
wprintf(L"ENV32BIT: Error: pointer should be 4 bytes. Exiting.");
exit(0);
}
wprintf(L"Diagnostics: we are running in 32-bit mode.\n");
#else
#error "Must define either ENV32BIT or ENV64BIT".
#endif
シンプルなチェック3/3:堅牢なコンパイル時間チェック
一般的なルールは、「すべての#defineはエラーを生成する#elseで終わる必要がある」です。
#if defined(ENV64BIT)
// 64-bit code here.
#elif defined (ENV32BIT)
// 32-bit code here.
#else
// INCREASE ROBUSTNESS. ALWAYS THROW AN ERROR ON THE ELSE.
// - What if I made a typo and checked for ENV6BIT instead of ENV64BIT?
// - What if both ENV64BIT and ENV32BIT are not defined?
// - What if project is corrupted, and _WIN64 and _WIN32 are not defined?
// - What if I didn't include the required header file?
// - What if I checked for _WIN32 first instead of second?
// (in Windows, both are defined in 64-bit, so this will break codebase)
// - What if the code has just been ported to a different OS?
// - What if there is an unknown unknown, not mentioned in this list so far?
// I'm only human, and the mistakes above would break the *entire* codebase.
#error "Must define either ENV32BIT or ENV64BIT"
#endif
2017-01-17の更新
からのコメント@AI.G
:
4年後(以前は可能だったかどうかわからない)に、静的アサートを使用してランタイムチェックをコンパイル時のチェックに変換できます:static_assert(sizeof(void *)== 4);。今ではすべてコンパイル時に行われます:)
付録A
偶然にも、上記のルールはコードベース全体の信頼性を高めるために適応させることができます:
- すべてのif()ステートメントは、警告またはエラーを生成する「else」で終わります。
- すべてのswitch()ステートメントは、警告またはエラーを生成する「デフォルト:」で終わります。
これがうまく機能する理由は、正しいコードを実行するために、「else」部分の(時々欠陥のある)ロジックに依存せずに、すべてのケースを事前に考えることを強制するためです。
私はこのテクニックを(他の多くの中で)30,000ラインプロジェクトを作成するために使用しました。このプロジェクトは、最初に運用環境に配置された日(12か月前)から完璧に機能しました。