C++コードが32ビットと64ビットでコンパイルされているかどうかを確実に判断する方法を探しています。マクロを使用した合理的な解決策と考えられるものを思いつきましたが、これが失敗する可能性のあるケースを考えられるかどうか、またはこれを行うためのより良い方法があるかどうかを知りたいと思いました。クロスプラットフォームの複数コンパイラ環境でこれを実行しようとしていることに注意してください。
#if ((ULONG_MAX) == (UINT_MAX))
# define IS32BIT
#else
# define IS64BIT
#endif
#ifdef IS64BIT
DoMy64BitOperation()
#else
DoMy32BitOperation()
#endif
ありがとう。
残念ながら、主要なコンパイラ全体で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
別の簡単な方法は、これらの変数をコンパイラーのコマンド行から設定することです。
template<int> void DoMyOperationHelper();
template<> void DoMyOperationHelper<4>()
{
// do 32-bits operations
}
template<> void DoMyOperationHelper<8>()
{
// do 64-bits operations
}
// helper function just to hide clumsy syntax
inline void DoMyOperation() { DoMyOperationHelper<sizeof(size_t)>(); }
int main()
{
// appropriate function will be selected at compile time
DoMyOperation();
return 0;
}
残念ながら、クロスプラットフォーム、クロスコンパイラ環境では、純粋にコンパイル時にこれを行うための信頼できる方法はありません。
したがって、信頼性のみの方法はつの単純なチェックを組み合わせることです
set必要な#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
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
一般的なルールは、「#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
@AI.G
からのコメント:
4年後(以前は可能かどうかわからない)静的アサートstatic_assert(sizeof(void *)== 4);を使用して、実行時チェックをコンパイル時チェックに変換できます。これで、コンパイル時にすべて完了しました:)
偶発的に、上記のルールは、コードベース全体の信頼性を高めるために適用できます。
これがうまく機能する理由は、正しいコードを実行するために「他の」部分の(場合によっては欠陥のある)ロジックに依存せずに、事前にすべてのケースを考えるように強制するためです。
私はこの手法を(他の多くの中でも)使用して、実稼働環境に最初に展開された日(12か月前)から完璧に機能する30,000行のプロジェクトを作成しました。
stdint.h
で定義されているマクロを使用できるはずです。特にINTPTR_MAX
はまさにあなたが必要とする値です。
#include <cstdint>
#if INTPTR_MAX == INT32_MAX
#define THIS_IS_32_BIT_ENVIRONMENT
#Elif INTPTR_MAX == INT64_MAX
#define THIS_IS_64_BIT_ENVIRONMENT
#else
#error "Environment not 32 or 64-bit."
#endif
Microsoftのコンパイラの一部(すべて?)のバージョンにはstdint.h
が付属していません。理由はわかりませんが、これは標準ファイルだからです。使用できるバージョンは次のとおりです。 http://msinttypes.googlecode.com/svn/trunk/stdint.h
これはWindowsで最初は機能しません。 32ビットまたは64ビットウィンドウ用にコンパイルしている場合、longとintはどちらも32ビットです。ポインターのサイズが8バイトかどうかを確認する方がおそらく信頼性の高いルートだと思います。
これを行うことができます:
#if __WORDSIZE == 64
char *size = "64bits";
#else
char *size = "32bits";
#endif
Try this:
#ifdef _WIN64
// 64 bit code
#Elif _WIN32
// 32 bit code
#else
if(sizeof(void*)==4)
// 32 bit code
else
// 64 bit code
#endif
「64ビットでコンパイル」はC++では十分に定義されていません。
C++は、int、long、void *
などのサイズの下限のみを設定します。 64ビットプラットフォーム用にコンパイルされた場合でも、intが64ビットであるという保証はありません。モデルでは、たとえば23ビットint
sおよびsizeof(int *) != sizeof(char *)
64ビットプラットフォームでは、さまざまな プログラミングモデル があります。
最善の策は、プラットフォーム固有のテストです。 2番目に優れた移植性のある決定は、whatが64ビットでより具体的でなければなりません。
アプローチはそれほど遠くありませんでしたが、long
とint
が同じサイズであるかどうかだけをチェックしています。理論的には、両方とも64ビットである可能性があり、その場合、両方とも32ビットであると仮定すると、チェックは失敗します。以下は、相対的なサイズではなく、タイプ自体のサイズを実際にチェックするチェックです。
#if ((UINT_MAX) == 0xffffffffu)
#define INT_IS32BIT
#else
#define INT_IS64BIT
#endif
#if ((ULONG_MAX) == 0xfffffffful)
#define LONG_IS32BIT
#else
#define LONG_IS64BIT
#endif
原則として、最大値を持つシステム定義マクロがある任意のタイプに対してこれを行うことができます。
標準では、long long
が32ビットシステムでも少なくとも64ビットである必要があることに注意してください。
人々は、プログラムが32-bit
または64-bit
でコンパイルされているかどうかを判断しようとする方法をすでに提案しています。
また、c ++ 11機能static_assert
を使用して、アーキテクチャが意図したとおりであることを確認する(「リラックスする」)ことができることを付け加えます。
したがって、マクロを定義する場所で:
#if ...
# define IS32BIT
static_assert(sizeof(void *) == 4, "Error: The Arch is not what I think it is")
#Elif ...
# define IS64BIT
static_assert(sizeof(void *) == 8, "Error: The Arch is not what I think it is")
#else
# error "Cannot determine the Arch"
#endif
以下のコードは、ほとんどの現在の環境で正常に機能します。
#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)
#define IS64BIT 1
#else
#define IS32BIT 1
#endif
すべての環境でプロジェクト構成を使用できる場合、64ビットおよび32ビットのシンボルを簡単に定義できます。したがって、次のようなプロジェクト構成になります。
32ビットデバッグ
32ビットリリース
64ビットデバッグ
64ビットリリース
編集:これらは一般的な設定であり、ターゲット設定ではありません。好きな名前を付けてください。
それができないなら、私はジャレッドのアイデアが好きです。
32ビットと64ビットのソースを異なるファイルに配置し、ビルドシステムを使用して適切なソースファイルを選択します。
この回答をユースケースとして追加し、 another answer で説明されているランタイムチェックの完全な例を追加します。
これは、プログラムが64ビットとしてコンパイルされたのか、32ビットとしてコンパイルされたのか(またはその他の点について)エンドユーザーに伝えるために私が取ったアプローチです。
version.h
#ifndef MY_VERSION
#define MY_VERSION
#include <string>
const std::string version = "0.09";
const std::string Arch = (std::to_string(sizeof(void*) * 8) + "-bit");
#endif
test.cc
#include <iostream>
#include "version.h"
int main()
{
std::cerr << "My App v" << version << " [" << Arch << "]" << std::endl;
}
コンパイルとテスト
g++ -g test.cc
./a.out
My App v0.09 [64-bit]