残念ながら、クロスプラットフォーム、クロスコンパイラ環境では、これを純粋にコンパイル時に実行するための単一の信頼できる方法はありません。
- プロジェクト設定に欠陥があるか破損している場合(特にVisual Studio 2008 SP1の場合)、_WIN32と_WIN64の両方が未定義になることがあります。
- 「Win32」というラベルの付いたプロジェクトは、プロジェクト構成エラーのために64ビットに設定される可能性があります。
- Visual Studio 2008 SP1では、現在の#defineによると、インテリセンスがコードの正しい部分をグレー表示しない場合があります。これにより、コンパイル時にどの#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年1月17日更新
からのコメント@AI.G
:
4年後(以前は可能かどうかはわかりません)、static assert:static_assert(sizeof(void *)== 4);を使用して、実行時チェックをコンパイル時チェックに変換できます。今ではすべてコンパイル時に行われます:)
付録A
ちなみに、上記のルールは、コードベース全体の信頼性を高めるために適合させることができます。
- すべてのif()ステートメントは、警告またはエラーを生成する「else」で終了します。
- すべてのswitch()ステートメントは、警告またはエラーを生成する「default:」で終了します。
これがうまく機能する理由は、正しいコードを実行するために「else」部分の(場合によっては欠陥のある)ロジックに依存せずに、すべてのケースを事前に考える必要があるためです。
私はこの手法を(他の多くの手法の中でも)使用して、最初に本番環境に導入された日(12か月前)から問題なく機能する30,000ラインのプロジェクトを作成しました。