modo elegante e sicuro per determinare se l'architettura è 32bit o 64bit
-
18-09-2019 - |
Domanda
Come dice il titolo, c'è un modo elegante e sicuro per determinare se l'architettura è 32bit o 64bit. Con eleganti, si può pensare a modo preciso, corretto, insomma, pulito e intelligente. Di sicuro, pensare alla sicurezza in termini di standard C89 / C99, e l'indipendenza del sistema operativo.
Soluzione
La dimensione dei puntatori non è davvero una buona cosa per testare - non c'è molto in serie C che si può fare con il risultato di tale prova comunque
. Il mio suggerimento è di prova ((size_t)-1)
, le dimensioni dell'oggetto più grande che comprende C:
if ((size_t)-1 > 0xffffffffUL)
{
printf("> 32 bits\n");
}
else
{
printf("<= 32 bits\n");
}
Se è maggiore di 0xffffffffUL
allora si può in linea di principio avere oggetti più grandi di byte 2**32 - 1
, che sembra un test più significativo di un nebuloso "32 bit contro i 64 bit".
(ad esempio, se si sa che il valore massimo di size_t
è solo 2**32 - 1
, allora non ha senso cercare di mmap()
una regione più grande di 1 o 2 GB).
Altri suggerimenti
risposta breve: non
risposta lunga: dipende da troppe combinazioni di OS / compilatore. Per esempio in fase di esecuzione, su linux è possibile interrogare il filesystem proc, mentre su Windows è possibile interrogare il registro.
Si può dimostrare che il compilatore che vengono utilizzati per la compilazione ha un 32/64 bits di destinazione utilizzando qualcosa di simile:
bool is_32bit() {
return sizeof(int *) == 4;
}
bool is_64bit() {
return sizeof(int *) == 8;
}
questo potrebbe opere in alcune ipotesi (per esempio funziona in fase di esecuzione). È possibile cercare in fase di compilazione #define
per la vostra piattaforma, ma è un casino ben noto.
Se si utilizza GCC (come indicato nei tag), è possibile verificare, come test in fase di compilazione
#if __SIZEOF_POINTER__ == 8
per scoprire se si tratta di un sistema a 64 bit. Assicurarsi che la versione GCC si sta utilizzando definisce __SIZEOF_POINTER__
a tutti prima di utilizzarlo.
Il modo più comune è quello di testare sizeof(void*)
e sizeof(int)
(notare che essi non devono necessariamente essere lo stesso).
Un'altra possibilità su CPU x86 / x64 è testare per la bandiera 'lm'. Se è presente la CPU capisce il set di istruzioni AMD64.
Una tecnica sicura e portatile è purtroppo impossibile (perché sicuro e portatile permette solo le regole del C standard).
sizeof(int)
con alcuni dei compilatori più comuni può dare 4 per una piattaforma a 32 bit e 8 per una piattaforma a 64 bit, ma questo non è garantito.
Tutto lo standard C dice è che un int dovrebbe essere la dimensione 'naturale' per i calcoli sul bersaglio, e così molti compilatori hanno lasciato sizeof (int) come 4 anche in un mondo a 64 bit, per il fatto che si tratta di 'sufficiente' .
sizeof(void*)
è meglio perché un puntatore deve essere la dimensione appropriata per affrontare l'intero spazio di indirizzamento. sizeof(void*)
è quindi probabile per darvi 4 o 8 a seconda dei casi.
Tecnicamente, però, anche questo non è garantito come sizeof ti dà il numero di byte necessari per memorizzare qualcosa, e un byte non deve essere di 8 bit. Un byte è tecnicamente la più piccola unità indirizzabile della memoria che avviene solo per essere 8 bit sulla maggior parte delle piattaforme di persone sono abituati. 8 bit indirizzabile è molto comune, ma lavoro con chip che sono 16 bit indirizzabili e dimensione di parola di 16 bit (così sizeof(int)
è 1).
Quindi, se la vostra dimensione in byte non è a 8 bit, quindi sizeof(void*)
potrebbe darvi una serie di valori.
D'altra parte, se si sta semplicemente cercando di distinguere tra x86 e x64 (32 bit e 64 processori bit PC) quindi sizeof (void *) saranno sufficienti, e portatili compilatori tutto.
32 bit sulla riva codice o 32 bit sulla banca dati. :-) 8086 processori avevano dati a 16 bit con memoria codice a 20 bit. Inoltre, le moderne macchine Havard fanno cose strane con la separazione di codice / dati ...
Si potrebbe verificare l'istruzione cpuid
per processori x86. Altre famiglie di processori non possono avere un tale istruzione ... YMMV.
int iedx;
__asm
{
mov eax, 0x80000001;
cpuid;
mov, iedx,edx;
}
if (iedx & (1 << 29))
{
return 1;
}
return 0;