Frage

Ich bin auf der Suche nach einem Weg, um zuverlässig festzustellen, ob C ++ Code in 32 vs 64-Bit kompiliert wird. Wir kommen mit dem, was wir denken, dass eine vernünftige Lösung ist mit Hilfe von Makros, aber war neugierig, wenn die Leute von Fällen denken könnte, wo dies nicht gelingen könnte, oder wenn es einen besseren Weg, dies zu tun. Bitte beachten Sie, wir versuchen, dies zu tun in einer plattformübergreifenden, mehrere Compiler-Umgebung.

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

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

Danke.

War es hilfreich?

Lösung

Leider gibt es kein Cross-Plattform-Makro, das 32/64-Bit in den wichtigsten Compiler definiert. Ich habe die effektivste Weg gefunden, dies zu tun ist die folgende.

Zuerst nehme ich meine eigene Darstellung. Ich ziehe es ENVIRONMENT64 / ENVIRONMENT32. Dann finde ich heraus, was alle wichtigen Compiler zur Bestimmung verwendet werden, wenn es sich um eine 64-Bit-Umgebung ist oder nicht und verwenden, die meine Variablen zu setzen.

// 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

Ein weiterer einfacher Weg ist, einfach diese Variablen aus der Compiler-Befehlszeile gesetzt.

Andere Tipps

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;
}

Leider ist in einer Cross-Plattform, Cross-Compiler-Umgebung gibt es keine einzige zuverlässige Methode, um diese rein bei der Kompilierung zu tun.

  • Sowohl _WIN32 und _WIN64 kann manchmal beide nicht definiert werden, wenn die Projekteinstellungen sind fehlerhaft oder beschädigt (insbesondere auf Visual Studio 2008 SP1).
  • Ein Projekt mit „Win32“ auf 64-Bit gesetzt werden kann, aufgrund eines Projektkonfigurationsfehler.
  • Ein Visual Studio 2008 SP1, manchmal die Intellisense grau nicht die richtigen Teile des Codes aus, entsprechend dem aktuellen #define. Dies macht es schwierig, genau zu sehen, welche #define wird bei der Kompilierung verwendet wird.

Daher ist die nur zuverlässig Methode zu kombinieren 3 einfache Prüfungen :

  • 1) Übersetzen Zeiteinstellung , und;
  • 2) Runtime Check , und;
  • 3) Robuste Kompilierung Überprüfung .

Einfache Kontrolle 1/3: Kompilieren Zeiteinstellung

Wählen Sie eine Methode, um gesetzt die erforderlichen #define variabel. Ich schlage vor, die Methode von @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

Einfache Kontrolle 2/3: Laufzeitprüfung

In main (), überprüfen Sie, ob sizeof () sinnvoll ist:

#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

Einfache Kontrolle 3/3: Robust Kompilierung Überprüfung

Die allgemeine Regel ist „jeder #define muss in einem #else enden, die einen Fehler erzeugt“.

#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

Aktualisieren 2017.01.17

Kommentar von @AI.G:

  

4 Jahre später (weiß nicht, ob es möglich war, bevor) Sie können konvertieren   die Laufzeitprüfung zu kompilieren Zeit eine mit statischem assert:   static_assert (sizeof (void *) == 4) ;. Jetzt ist es bei der Kompilierung getan   :)

Anhang A

eventueller Stich, können die oben genannten Regeln angepasst werden, um Ihre gesamte Code-Basis zuverlässiger zu machen:

  • Jede if () Anweisung endet in einem "anderen", die eine Warnung oder einen Fehler erzeugt.
  • Jeder Schalter () Anweisung endet in einem „default“., Die eine Warnung oder einen Fehler erzeugt

Der Grund, warum dies gut funktioniert, ist, dass es Sie zwingt jeden einzelnen Fall im Voraus zu denken, und nicht darauf verlassen, (manchmal fehlerhaft) Logik in dem „else“ Teil den richtigen Code auszuführen.

habe ich diese Technik (unter vielen anderen) ein 30.000 Linie Projekt zu schreiben, die einwandfrei ab dem Tag arbeitete er zunächst in der Produktion eingesetzt wurde (dh 12 Monate war vor).

Es sollte möglich sein, die Makros zu verwenden, definiert in stdint.h . Insbesondere INTPTR_MAX ist genau der Wert, den Sie benötigen.

#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

Einige (alle?) Versionen von Microsofts Compiler kommen nicht mit stdint.h. Nicht sicher, warum, da es sich um eine Standard-Datei ist. Hier ist eine Version, die Sie verwenden können: http://msinttypes.googlecode.com/svn/trunk/stdint.h

Das wird nicht für einen Start unter Windows arbeiten. Longs und ints sind beide 32 Bits, ob Sie für 32-Bit oder 64-Bit-Windows sind kompilieren. Ich würde Überprüfung denken, wenn die Größe eines Zeigers ist 8 Bytes ist wahrscheinlich ein zuverlässiger Weg.

Sie können dies tun:

#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

"in 64-Bit-Compiled" ist in C ++ nicht gut definiert.

C ++ stellt nur niedrigere Grenzwerte für Größen wie int, long und void *. Es gibt keine Garantie dafür, dass 64-Bit auch int ist, wenn eine 64-Bit-Plattform erstellt. Das Modell ermöglicht z.B. 23-Bit-ints und sizeof(int *) != sizeof(char *)

Es gibt verschiedene Programmiermodelle rel="nofollow für 64-Bit-Plattformen .

Ihre beste Wette ist ein plattformspezifische Tests. Ihre zweitbeste, tragbare Entscheidung muss präziser in was ist 64 Bit.

Ihr Ansatz war auch nicht weit weg, aber Sie prüfen nur, ob long und int von gleicher Größe sind. Theoretisch könnten sie 64 beide Bits sein, wobei in diesem Fall Ihre Überprüfung fehlschlagen würde, die beide unter der Annahme, 32 Bits. Hier ist eine Überprüfung, die tatsächlich überprüft die Größe der Typen selbst, nicht ihre relative Größe:

#if ((UINT_MAX) == 0xffffffffu)
    #define INT_IS32BIT
#else
    #define INT_IS64BIT
#endif
#if ((ULONG_MAX) == 0xfffffffful)
    #define LONG_IS32BIT
#else
    #define LONG_IS64BIT
#endif

Im Prinzip können Sie dies für jede Art, für die Sie ein System definiert Makro mit dem Maximalwert haben.

Beachten Sie, dass die Standard-long long erfordert mindestens 64 Bits auch auf 32-Bit-Systeme.

Menschen bereits vorgeschlagen, Methoden, wenn das Programm, um zu bestimmen versuchen, wird in 32-bit oder 64-bit zusammengestellt werden.

Und ich möchte hinzufügen, dass Sie 11 Feature static_assert die C ++ verwenden, um sicherzustellen, dass die Architektur ist das, was Sie denken, es ist ( „entspannen“).

So in dem Ort, wo Sie definieren die Makros:

#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

Im Folgenden Code funktioniert gut für die meisten aktuellen Umgebungen:

  #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

Wenn Sie Projektkonfigurationen in allen Umgebungen verwenden können, das wäre ein 64- und 32-Bit-Symbol leicht machen definieren. So können Sie Projektkonfigurationen wie diese haben würde:

32-Bit-Debug
32-Bit-Version
64-Bit-Debug
64-Bit-Version

EDIT: Dies sind allgemeine Konfigurationen, nicht abgezielt Konfigurationen. Rufen Sie sie, was Sie wollen.

Wenn Sie das nicht können, wie ich Jared Idee.

Ich würde Platz 32-Bit- und 64-Bit-Quellen in verschiedenen Dateien und dann die entsprechenden Quelldateien wählen Sie das Build-System verwendet wird.

Ich füge diese Antwort als Anwendungsfall und vollständige Beispiel für die Runtime-Check in einer anderen Antwort .

Dies ist der Ansatz, den ich habe für den Transport zum Endverbraucher genommen, ob das Programm als 64-Bit- oder 32-Bit kompiliert wurde (oder andere, was das betrifft):

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;
}

Übersetzen und Test

g++ -g test.cc
./a.out
My App v0.09 [64-bit]
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top