web-dev-qa-db-ja.com

C ++での32ビットと64ビットの決定

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

#if ((ULONG_MAX) == (UINT_MAX))
# define IS32BIT
#else
# define IS64BIT
#endif

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

ありがとう。

125
Joe Corkery

残念ながら、主要なコンパイラ全体で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

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

95
JaredPar
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;
}
97

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

  • プロジェクト設定に欠陥があるか破損している場合、(特にVisual Studio 2008 SP1の場合)_WIN32と_WIN64の両方が両方未定義になることがあります。
  • プロジェクト構成エラーのため、「Win32」というラベルのプロジェクトが64ビットに設定される可能性があります。
  • Visual Studio 2008 SP1では、現在の#defineに従って、インテリセンスがコードの正しい部分をグレーアウトしない場合があります。これにより、コンパイル時に使用されている#defineを正確に確認することが難しくなります。

したがって、信頼性のみの方法はつの単純なチェックを組み合わせることです

  • 1)コンパイル時間設定、および;
  • 2)実行時チェック、および;
  • 3)堅牢なコンパイル時チェック

シンプルチェック1/3:コンパイル時間設定

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

シンプルチェック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()ステートメントは、警告またはエラーを生成する「デフォルト:」で終了します。

これがうまく機能する理由は、正しいコードを実行するために「他の」部分の(場合によっては欠陥のある)ロジックに依存せずに、事前にすべてのケースを考えるように強制するためです。

私はこの手法を(他の多くの中でも)使用して、実稼働環境に最初に展開された日(12か月前)から完璧に機能する30,000行のプロジェクトを作成しました。

42
Contango

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

26
alex tingle

これはWindowsで最初は機能しません。 32ビットまたは64ビットウィンドウ用にコンパイルしている場合、longとintはどちらも32ビットです。ポインターのサイズが8バイトかどうかを確認する方がおそらく信頼性の高いルートだと思います。

15
mattnewport

これを行うことができます:

#if __WORDSIZE == 64
char *size = "64bits";
#else
char *size = "32bits";
#endif
8
Anoop
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
6
emj8321

「64ビットでコンパイル」はC++では十分に定義されていません。

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

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

最善の策は、プラットフォーム固有のテストです。 2番目に優れた移植性のある決定は、whatが64ビットでより具体的でなければなりません。

4
peterchen

アプローチはそれほど遠くありませんでしたが、longintが同じサイズであるかどうかだけをチェックしています。理論的には、両方とも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ビットである必要があることに注意してください。

3
cmaster

人々は、プログラムが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
3
Ameen

以下のコードは、ほとんどの現在の環境で正常に機能します。

  #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
2
Alex Byrth

すべての環境でプロジェクト構成を使用できる場合、64ビットおよび32ビットのシンボルを簡単に定義できます。したがって、次のようなプロジェクト構成になります。

32ビットデバッグ
32ビットリリース
64ビットデバッグ
64ビットリリース

編集:これらは一般的な設定であり、ターゲット設定ではありません。好きな名前を付けてください。

それができないなら、私はジャレッドのアイデアが好きです。

1
Jon Seigel

32ビットと64ビットのソースを異なるファイルに配置し、ビルドシステムを使用して適切なソースファイルを選択します。

1
big-z

この回答をユースケースとして追加し、 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]
0
vallismortis