119


46

私はCコードが32対64ビットでコンパイルされているかどうかを確実に判断する方法を探しています。 私たちはマクロを使った合理的な解決策だと思うものを思いつきましたが、これが失敗するかもしれないケースを考えることができるかどうか、またはこれをするより良い方法があるかどうかを知りたかったです。 クロスプラットフォームの複数コンパイラ環境でこれを実行しようとしていることに注意してください。

#if((ULONG_MAX)==(UINT_MAX))#define IS32BIT#その他#define IS64BIT #endif

#ifdef IS64BIT DoMy64BitOperation()#else DoMy32BitOperation()#endif

ありがとう。

14 Answer


94


template void DoMyOperationHelper();

template <> void DoMyOperationHelper <4>(){// 32ビット操作を行います}

template <> void DoMyOperationHelper <8>(){// 64ビット操作を行います}

// helper function just to hide clumsy syntax
インラインvoid DoMyOperation(){DoMyOperationHelper();} }

int main(){//コンパイル時に適切な関数が選択されますDoMyOperation();

0を返します。 }


92


残念ながら、主要なコンパイラで32/64ビットを定義するクロスプラットフォームマクロはありません。 これを行う最も効果的な方法は次のとおりです。

まず自分の表現を選びます。 私はENVIRONMENT64 / ENVIRONMENT32が好きです。 それから私はそれが64ビット環境であるかどうかを決定するためにすべての主要なコンパイラが使っていることを見つけ、それを使って変数を設定します。

// Check windows
#if _WIN32 || _WIN64 #if _WIN64 #define ENVIRONMENT64 #else #define ENVIRONMENT32 #endif #endif

// Check GCC
#if __GNUC__ #if __x86_64__ || __ppc64__ #define ENVIRONMENT64 #else #define ENVIRONMENT32 #endif #endif

もう1つの簡単な方法は、これらの変数をコンパイラのコマンドラインから設定することです。


40


残念ながら、クロスプラットフォーム、クロスコンパイラ環境では、純粋にコンパイル時にこれを行うための信頼できる方法はありません。

  • プロジェクト設定に欠陥があるか破損している場合(特に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が定義されている場合(ENV64BIT)(sizeof(void *)!= 8){wprintf(L "ENV64BIT:エラー:ポインタは8バイトでなければなりません。) 終了します。 ")exit(0);} wprintf(L"診断:64ビットモードで実行しています。 (L "ENV32BIT:エラー:ポインタは4バイトです。 終了します。 "); exit(0);} wprintf(L"診断:32ビットモードで実行しています。\ n "); #else #error" ENV32BITまたはENV64BITを定義する必要があります。 #endif

簡単なチェック3/3:堅牢なコンパイル時チェック

一般的な規則は「すべての#defineはエラーを生成する#elseで終わらなければならない」というものです。

#if defined(ENV64BIT)//ここでは64ビットコード。 #elif defined(ENV32BIT)//ここでは32ビットコード。 #else // ROBUSTNESSを増やします。 常にELSEにエラーが発生します。 //  - タイプミスをしてENV64BITではなくENV6BITをチェックしたらどうなりますか? //  -  ENV64BITとENV32BITの両方が定義されていない場合はどうなりますか? //  - プロジェクトが破損していて、_WIN64と_WIN32が定義されていない場合はどうなりますか? //  - 必要なヘッダファイルをインクルードしなかった場合はどうなりますか //  -  2番目ではなく最初に_WIN32をチェックした場合はどうなりますか? //(Windowsでは、両方とも64ビットで定義されているため、コードベースが壊れます)//  - コードを別のOSに移植したばかりの場合はどうなりますか //  - これまでにこのリストに載っていない、未知の未知の未知数がある場合はどう? //私は人間です。上記の間違いはコードベース全体を壊すでしょう。 #error "ENV32BITまたはENV64BITのいずれかを定義する必要があります" #endif

更新2017-01-17

`@ AI.G`からのコメント:

4年後(以前は可能だったかどうかわからない)、スタティックアサートを使用して実行時チェックをコンパイル時チェックに変換することができます。static_assert(sizeof(void *)== 4);。 これですべてコンパイル時に行われました:) _

付録A

偶然にも、上記の規則はあなたのコードベース全体をより信頼できるものにするために適応させることができます。

  • すべてのif()文は、警告またはエラーを生成する「else」で終わります。

  • すべてのswitch()ステートメントは "default:"で終わります。これは警告またはエラーを生成します。

これがうまく機能するのは、正しいコードを実行するために「else」部分の(場合によっては欠陥のある)ロジックに頼らずに、すべてのケースを事前に検討する必要があるためです。

私はこの手法を(とりわけ12ヶ月前に)最初に本番環境に展開した日から完璧に機能する30,000ラインのプロジェクトを書くために(他の多くの中で)使用しました。


24


あなたは stdint.hで定義されているマクロを使うことができるはずです。 特に `INTPTR_MAX`はまさにあなたが必要とする値です。

#include #if INTPTR_MAX == INT32_MAX #define THIS_IS_32_BIT_ENVIRONMENT #elif INTPTR_MAX == INT64_MAX #define THIS_IS_64_BIT_ENVIRONMENT #else #error#32または64ビットの環境ではありません。 #endif

Microsoftのコンパイラの(すべての?)バージョンには `stdint.h`が付いていません。 理由は定かではありません。標準ファイルですから。 これがあなたが使うことができるバージョンです: http://msinttypes.googlecode.com/svn/trunk/stdint.hhttp://msinttypes.googlecode.com/svn/trunk/stdint.h


15


最初はWindows上ではうまくいきません。 32ビットまたは64ビットウィンドウ用にコンパイルしているかどうかにかかわらず、Longsとintはどちらも32ビットです。 私はポインタのサイズが8バイトであるかどうかをチェックすることはおそらくもっと信頼できるルートだと思うでしょう。


8


あなたはこれをすることができます:

#if __WORDSIZE == 64 char * size = "64bits"; #else char * size = "32bits"; #endif


6


これを試してください。#ifdef _WIN64
// 64 bit code
#elif _WIN32
// 32 bit code
#else if(sizeof(void *)== 4)

// 32ビットコード

// 64ビットコード#endif


4


「64ビットでコンパイルされる」はCではよく定義されていません。

Cはint、long、 void *`のようなサイズの下限だけを設定します。 64ビットプラットフォーム用にコンパイルされた場合でも、intが64ビットであるという保証はありません。 モデルは可能にします。 23ビットの `int`と sizeof(int *)!= sizeof(char *) `

64ビットプラットフォーム用には、さまざまな プログラミングモデルがあります。

あなたの最善の策はプラットフォーム固有のテストです。 2番目に良い、移植性のある決定は、64ビットでより明確にする必要があります。


3


プログラムが 32-bit`でコンパイルされているのか、 64-bit`でコンパイルされているのかを判断しようとする方法をすでに提案しています。

そして、私はあなたがアーキテクチャがあなたがそれが思っているものであることを確認するためにあなたがC 11の機能 `static_assert`を使うことができることを付け加えたいです(「リラックスするために」)。

だからあなたがマクロを定義する場所では:

#if ... #IS32BIT static_assert(sizeof(void *)== 4、 "Error:Archは私が思うところではないです")#elif ... #define IS64BIT static_assert(sizeof(void *)== 8、 "エラー:Archは私が思うものではありません" #else#error


2


あなたのアプローチはそれほど遠くはありませんでした、しかしあなたはただ long`と int`が同じサイズであるかどうか調べるだけです。 理論的には、両方とも64ビットである可能性があります。その場合、両方とも32ビットであると仮定して、あなたのチェックは失敗します。 これは、実際の型のサイズではなく、実際の型のサイズをチェックするチェックです。

#if((UINT_MAX)== 0xffffffffu)#define INT_IS32BIT#その他#define INT_IS64BIT #endif #if((ULONG_MAX)== 0xfffffffful)#define LONG_IS32BIT#その他#define

原則として、最大値を持つシステム定義マクロがあるすべてのタイプに対してこれを実行できます。

32ビットシステムであっても標準では少なくとも64ビットであることが `long long`を要求していることに注意してください。