Szukam sposobu, aby wiarygodnie określić, czy kod C ++ jest kompilowany w wersji 32 vs 64 bit. Wymyśliliśmy to, co uważamy za rozsądne rozwiązanie przy użyciu makr, ale byliśmy ciekawi, czy ludzie mogą wymyślić przypadki, w których może się to nie udać, lub czy istnieje lepszy sposób na zrobienie tego. Należy pamiętać, że próbujemy to zrobić w wieloplatformowym środowisku kompilatorów.
#if ((ULONG_MAX) == (UINT_MAX))
# define IS32BIT
#else
# define IS64BIT
#endif
#ifdef IS64BIT
DoMy64BitOperation()
#else
DoMy32BitOperation()
#endif
Dzięki.
c++
32bit-64bit
conditional-compilation
Joe Corkery
źródło
źródło
stdint.h
może być twoim przyjacielem lub być może będziesz musiał opracować własne, odpowiednie typy.Odpowiedzi:
Niestety nie ma makra wieloplatformowego, które definiuje 32/64 bity w głównych kompilatorach. Najskuteczniejszy sposób, aby to zrobić, jest następujący.
Najpierw wybieram własną reprezentację. Wolę ŚRODOWISKO64 / ŚRODOWISKO32. Następnie dowiaduję się, czego używają wszystkie główne kompilatory do określenia, czy jest to środowisko 64-bitowe, czy nie, i używam tego do ustawiania moich zmiennych.
Inną łatwiejszą drogą jest po prostu ustawienie tych zmiennych z wiersza poleceń kompilatora.
źródło
#if _WIN32 || _WIN64
...#elif __GNUC__
...#else
# error "Missing feature-test macro for 32/64-bit on this compiler."
?źródło
size_t
jest wystarczająco duży, aby pomieścić rozmiar dowolnego przydzielonego obiektu w systemie. Zwykle jest to to, co chcesz wiedzieć podczas kompilacji warunkowej. Jeśli tego nie chcesz, możesz użyć tego fragmentu z innym typem zamiastsize_t
. Na przykład może to byćvoid*
.Niestety, w środowisku wieloplatformowym i kompilatorach wieloplatformowych nie ma jednej niezawodnej metody robienia tego wyłącznie w czasie kompilacji.
Dlatego jedyną niezawodną metodą jest połączenie 3 prostych kontroli :
Proste sprawdzenie 1/3: ustawienie czasu kompilacji
Wybierz dowolną metodę, aby ustawić wymaganą zmienną #define. Proponuję metodę z @JaredPar:
Proste sprawdzenie 2/3: sprawdzenie w czasie wykonywania
W main () dwukrotnie sprawdź, czy sizeof () ma sens:
Proste sprawdzenie 3/3: Solidne sprawdzanie czasu kompilacji
Ogólna zasada brzmi: „każdy #define musi kończyć się #else, który generuje błąd”.
Aktualizacja 2017-01-17
Komentarz od
@AI.G
:załącznik A
Nawiasem mówiąc, powyższe reguły można dostosować, aby cała baza kodu była bardziej niezawodna:
Powodem, dla którego to działa dobrze, jest to, że zmusza cię do przemyślenia każdego pojedynczego przypadku z wyprzedzeniem i nie polega na (czasem błędnej) logice w części „else”, aby wykonać poprawny kod.
Użyłem tej techniki (między innymi), aby napisać projekt 30 000 linii, który działał bezbłędnie od dnia pierwszego wdrożenia do produkcji (czyli 12 miesięcy temu).
źródło
sizeof(void*)
czy jest rozwiązywany w czasie kompilacji czy w czasie wykonywania? jeśli jest w czasie kompilacji, to w czasie wykonywania sprawdzenie zawsze będzieif(8!=8){...}
.static_assert(sizeof(void*) == 4);
. Teraz wszystko gotowe w czasie kompilacji :)static_assert(sizeof(void*) * CHAR_BIT == 32)
jest bardziej wyrazista i technicznie poprawna (chociaż nie znam żadnej architektury, w której bajty mają inną liczbę bitów niż 8)Powinieneś móc używać makr zdefiniowanych w
stdint.h
. W szczególnościINTPTR_MAX
jest to dokładnie taka wartość, jakiej potrzebujesz.Niektóre (wszystkie?) Wersje kompilatora Microsoftu nie są dostarczane z
stdint.h
. Nie wiem dlaczego, ponieważ jest to standardowy plik. Oto wersja, której możesz użyć:http://msinttypes.googlecode.com/svn/trunk/stdint.hźródło
<stdint.h>
i<cstdint>
. Jeśli chodzi o obecny stan rzeczy - biblioteka VC ++ pochodzi z Dinkumware (nadal tak jest - stamtąd też został wzięty TR1), ale z tego, co pamiętam, czytałem na VCBlog, przechodzi dość znaczną refaktoryzację, aby skompilować się czysto/clr
, współpracuje ze wszystkimi MSVC niestandardowe typy, takie jak__int64
i tak dalej - dlatego nie jest to tak proste, jak po prostu pobranie go i umieszczenie w następnej wersji kompilatora.Na początek to nie zadziała w systemie Windows. Długie i int są 32-bitowe, niezależnie od tego, czy kompilujesz dla okien 32-bitowych, czy 64-bitowych. Myślę, że sprawdzenie, czy rozmiar wskaźnika wynosi 8 bajtów, jest prawdopodobnie bardziej niezawodną trasą.
źródło
sizeof(void*) == 8 ? Do64Bit() : Do32Bit();
. Może to nadal pozostawić nieużywaną funkcję w pliku binarnym, ale wyrażenie jest prawdopodobnie skompilowane tylko do wywołania funkcji „właściwej”.template<int> struct Thing; template<> struct Thing<4> { typedef uint32_t type; }; template<> struct Thing<8> { typedef uint64_t type; }; typedef Thing<sizeof(void*)>::type thingtype;
Możesz to zrobić:
źródło
źródło
„Kompilacja w wersji 64-bitowej” nie jest dobrze zdefiniowana w C ++.
C ++ ustawia tylko dolne limity dla rozmiarów, takich jak int, long i
void *
. Nie ma gwarancji, że int jest 64-bitowy, nawet po skompilowaniu dla platformy 64-bitowej. Model dopuszcza np. 23 bityint
isizeof(int *) != sizeof(char *)
Istnieją różne modele programowania dla platform 64-bitowych.
Najlepszym rozwiązaniem jest test specyficzny dla platformy. Twój drugi najlepszy przenośne decyzja musi być bardziej szczegółowe w co jest 64-bitowy.
źródło
Twoje podejście nie było zbyt odległe, ale sprawdzasz tylko, czy
long
i czyint
są tej samej wielkości. Teoretycznie oba mogą mieć 64 bity, w takim przypadku twój test nie powiedzie się, zakładając, że oba mają 32 bity. Oto kontrola, która faktycznie sprawdza rozmiar samych typów, a nie ich względny rozmiar:W zasadzie możesz to zrobić dla każdego typu, dla którego masz zdefiniowane przez system makro z wartością maksymalną.
Zauważ, że standard wymaga
long long
co najmniej 64 bitów, nawet w systemach 32-bitowych.źródło
#include <limits.h>
gdzieś przed#if
testami.Ludzie już zasugerowali metody, które spróbują określić, czy program jest kompilowany w
32-bit
lub64-bit
.I chcę dodać, że możesz użyć funkcji c ++ 11,
static_assert
aby upewnić się, że architektura jest taka, jaką myślisz („odprężyć się”).A więc w miejscu, w którym definiujesz makra:
źródło
static_assert(sizeof(void*) * CHAR_BIT == 32)
jest bardziej wyrazista i poprawna technicznie (chociaż nie znam żadnej architektury, w której bajty mają inną liczbę bitów niż 8)Poniższy kod działa dobrze w większości obecnych środowisk:
źródło
_WIN64
wymaga to już uwzględnienia<windows.h>
. Visual C ++, to lepiej użyć wbudowanego Definiuje kompilatora:_M_IX86
,_M_X64
,_M_ARM
,_M_ARM64
, itp__ppc64__
,__powerpc64__
i_ARCH_PPC64
. To łapie także AIX i inne platformy.Jeśli możesz używać konfiguracji projektu we wszystkich swoich środowiskach, ułatwiłoby to zdefiniowanie 64- i 32-bitowego symbolu. Więc miałbyś takie konfiguracje projektu:
32-bitowe debugowanie
32-bitowe wydanie
64-bitowe debugowanie
64-bitowe wydanie
EDYCJA: są to konfiguracje ogólne, a nie docelowe. Zadzwoń do nich, jak chcesz.
Jeśli nie możesz tego zrobić, podoba mi się pomysł Jareda.
źródło
Umieściłbym źródła 32-bitowe i 64-bitowe w różnych plikach, a następnie wybrałbym odpowiednie pliki źródłowe za pomocą systemu kompilacji.
źródło
-DBUILD_64BIT
. Często niektóre rzeczy są bardzo podobne do 32- i 64-bitowych, więc umieszczenie ich w tym samym pliku może być całkiem praktyczne.Pożyczanie od contango jest doskonałą odpowiedzią powyżej i łącząc ją z « lepszych makr, lepszy Flags » z Fluent C ++, można zrobić:
Następnie możesz go używać tak:
Lub korzystając z dodatkowego makra, które dodałem:
źródło
Dodaję tę odpowiedź jako przypadek użycia i kompletny przykład sprawdzania środowiska uruchomieniowego opisanego w innej odpowiedzi .
Oto podejście, które obrałem, aby przekazać użytkownikowi końcowemu, czy program został skompilowany jako 64-bitowy, czy 32-bitowy (lub inny, jeśli o to chodzi):
version.h
test.cc
Kompiluj i testuj
źródło