Domanda

Fino a poco tempo fa, avevo considerato la decisione maggior parte dei sistemi implementatori / fornitori per mantenere pianura int a 32 bit anche su macchine a 64 bit una sorta di espediente verruca. Con tipi moderno C99-dimensione fissa (int32_t e uint32_t, etc.) la necessità che vi sia un tipo intero standard di ciascuna dimensione 8, 16, 32, e 64 scompare lo più, e sembra int potrebbero benissimo essere fatta 64-bit.

Tuttavia, la più grande causa reale della dimensione delle int pianura in C deriva dal fatto che la C in sostanza non ha l'aritmetica sui tipi di piccoli-che-int. In particolare, se int è maggiore di 32 bit, il risultato di qualsiasi aritmetiche sui valori uint32_t trovi tipo signed int, che è piuttosto spiazzante.

E 'questo un buon motivo per tenere int permanentemente fissato a 32 bit su implementazioni reali? Sto propensione a dire di sì. Mi sembra come se ci potrebbe essere un enorme classe di usi di uint32_t che rompono quando int è più grande di 32 bit. Anche applicando il segno meno o complemento bit a bit operatore unario diventa pericoloso se non si esegue il cast di nuovo a uint32_t.

Naturalmente gli stessi problemi si applicano a uint16_t e uint8_t sulle attuali implementazioni, ma tutti sembrano essere consapevoli e utilizzato per trattandoli come tipi "piccolo-che-int".

È stato utile?

Soluzione

Come dici tu, penso che le regole di promozione sono davvero l'assassino. uint32_t sarebbe poi promuovere a int e tutto ad un tratto si avrebbe firmato aritmetica dove quasi tutti si aspettano non firmato.

Questo sarebbe in gran parte nascosto in luoghi in cui si fa indietro solo l'aritmetica e assegnare a un uint32_t. Ma potrebbe essere mortale nei luoghi in cui si fa il confronto alle costanti. Se il codice che si basa su tali confronti senza fare un cast esplicito è ragionevole, non lo so. Casting costanti come (uint32_t)1 può diventare molto noioso. Io personalmente, almeno uso sempre il U suffisso per le costanti che voglio essere firmato, ma questo già non è così leggibile come vorrei.

hanno anche in mente che uint32_t ecc non sono garantiti per esistere. Nemmeno uint8_t. L'applicazione di che è un'estensione da POSIX. Quindi, in questo senso, C come linguaggio è ben lungi dall'essere in grado di fare quella mossa.

Altri suggerimenti

"Reasonable Codice" ...

Beh ... la cosa di sviluppo è, si scrive e risolvere il problema e quindi funziona ... e poi ti fermi!

E forse sei stato bruciato un sacco in modo da rimanere bene entro i limiti di sicurezza di determinate caratteristiche, e forse non sei stato bruciato in quel particolare modo in modo che non si rendono conto che vi affidate ai qualcosa che potrebbe tipo-di cambiamento.

O anche che si sta contando su un bug.

Il Olden Mac 68000 compilatori, int era a 16 bit e lunga era 32. Ma anche allora il codice C più esistente assunto un int era 32, così tipico codice che avete trovato su un newsgroup non avrebbe funzionato. (Oh, e Mac non ha avuto printf, ma sto divagando.)

Allora, che cosa voglio arrivare è, sì, se si cambia niente , quindi alcune cose si romperà.

Con i tipi di dimensioni fisse moderno C99 (Int32_t e uint32_t, ecc) la necessità perché vi sia un numero intero normale tipo di ciascuno formato 8, 16, 32, e 64 in gran parte scompare,

C99 è typedef, non tipi a dimensione fissa di dimensioni fisso. Il C nativo intero tipi sono ancora char, short, int, long e long long. Essi sono ancora rilevanti.

Il problema con ILP64 è che ha una grande discrepanza tra tipi C e typedef C99.

  • int8_t = char
  • int16_t = breve
  • int32_t = tipo non standard
  • int64_t = int, long, o lunga lunga

64 bit modelli di programmazione: Perché LP64 :?

Purtroppo, il modello ILP64 fa non forniscono un modo naturale per descrivere i tipi di dati a 32 bit, e devono ricorrere a costrutti non portatili come __int32 per descrivere tali tipi. Questo rischia di causare problemi pratici nella produzione di codice che può essere eseguito su 32 e 64 bit senza piattaforme costruzioni #ifdef. E 'stato possibile portare grandi quantità di codice per LP64 modelli senza la necessità di apportare tali modifiche, mentre mantenendo l'investimento fatto in insiemi di dati, anche in casi in cui il Informazioni digitazione non è stato fatto visibile esternamente dall'applicazione.

DEC Alpha e OSF / 1 Unix è stata una delle prime versioni a 64 bit di Unix, ed è usato interi a 64 bit - un ILP64 architettura (che significa int, long e puntatori erano tutte le quantità a 64 bit). Essa ha causato un sacco di problemi.

Un problema che ho menzionato non si vedono - che è per questo che sto rispondendo a tutti dopo così tanto tempo - è che se si dispone di un 64-bit int, che formato voi usare per short? Entrambi i 16 bit (classico, cambiamento approccio nulla) e 32 bit (il radicale 'bene, un short dovrebbe essere la metà del tempo come int' approccio) presenterà alcuni problemi.

Con i <stdint.h> e <inttypes.h> intestazioni C99, si può codice per interi di dimensioni fisse - Se si sceglie di ignorare le macchine con 36-bit o 60-bit interi (che è almeno quasi-legittimo). Tuttavia, la maggior parte del codice non è scritto utilizzando questi tipi, e non ci sono in genere profondo e in gran parte nascosto (ma fondamentalmente errata) le assunzioni nel codice che verrà sconvolto se il modello discosti dalle variazioni esistenti.

modello LLP64 ultra-conservatore di Avviso Microsoft per Windows a 64 bit. Che è stato scelto perché troppo vecchio codice potrebbe rompersi se il modello a 32-bit è stato cambiato. Tuttavia, il codice che era stato portato su ILP64 o LP64 architetture non è stato immediatamente portatile per LLP64 a causa delle differenze. I teorici della cospirazione probabilmente dire che è stato volutamente scelto per rendere più difficile per il codice scritto per Unix a 64 bit per essere portato su Windows a 64 bit. In pratica, dubito che che era più di un felice (per Microsoft) effetto collaterale; il codice di Windows a 32 bit ha dovuto essere rivisto un sacco a fare uso del modello LP64 troppo.

C'è un linguaggio codice che avrebbe rotto se fossero interi a 64-bit, e lo vedo abbastanza spesso che penso che potrebbe essere chiamato ragionevole:

  • controllare se un valore è negativo testando se ((val & 0x80000000) != 0)

Questa si trova comunemente nel controllo codici di errore. Molte norme del codice di errore (come HRESULT della finestra) con il bit di 31 per rappresentare un errore. E il codice a volte verificare la presenza di tale errore sia da test bit 31 o, talvolta, verificando se l'errore è un numero negativo.

macro di Microsoft per testare HRESULT utilizzare entrambi i metodi - e sono sicuro che c'è una tonnellata di codice là fuori che fa simili senza usare le macro SDK. Se MS si era trasferito a ILP64, questo sarebbe un settore che ha causato il porting mal di testa che sono completamente evitati con il modello LLP64 (o il modello LP64).

Nota. Se non hai familiarità con termini come "ILP64", si prega di vedere il mini-glossario alla fine della risposta

Sono abbastanza sicuro che ci sono un sacco di codice (non necessariamente di Windows-oriented) là fuori che usi plain-old-int a codici di errore in attesa, assumendo che questi siano interi a 32 bit nel formato. E scommetto che ci sono un sacco di codice con tale regime stato di errore che utilizza anche entrambi i tipi di controlli (< 0 e bit 31 essendo set) e che sarebbe rompersi se spostato in una piattaforma ILP64. Questi controlli possono essere fatti di continuare a funzionare correttamente in entrambi i casi, se i codici di errore sono stati costruiti con cura in modo che estensione del segno ha avuto luogo, ma ancora una volta, molti di tali sistemi che ho visto costrutto i valori di errore da o-zione insieme un gruppo a campi di bit .

In ogni caso, non credo che questo sia un problema irrisolvibile con qualsiasi mezzo, ma io penso che sia una pratica di codifica abbastanza comune che avrebbe causato un sacco di codice per richiedere il fissaggio su se spostato in una piattaforma ILP64.

Si noti che anche io non credo che questo è stato uno dei motivi principali per Microsoft di scegliere il modello LLP64 (credo che la decisione è stata in gran parte determinata dalla compatibilità dei dati binaria tra i processi a 32-bit e 64-bit, come menzionato nel MSDN e su di Raymond Chen blog ).


Mini-Glossario per la piattaforma di programmazione terminologia Modello 64-bit:

  • ILP64: int, long, puntatori sono a 64-bit
  • LP64: long e puntatori sono a 64-bit, int è di 32-bit (? Utilizzato da molte piattaforme (la maggior parte) Unix)
  • LLP64: long long e puntatori sono 64 bit, int e long rimangono 32 bit (utilizzati sulle Win64)

Per ulteriori informazioni sui modelli di programmazione a 64 bit, vedere "Modelli di programmazione a 64 bit: Perché LP64? "

Mentre faccio codice non personalmente scrittura come questo, scommetto che è là fuori in più di un posto ... e, naturalmente, romperà se si modifica la dimensione di int.

int i, x = getInput();
for (i = 0; i < 32; i++)
{
    if (x & (1 << i))
    {
        //Do something
    }
}

Beh, non è come questa storia è tutto nuovo. Con la "maggior parte dei computer" si Presumo computer desktop medi. C'è già stata una transizione da 16 bit a 32 bit int. C'è qualcosa in tutto ciò che dice la stessa progressione non accadrà questa volta?

Non particolarmente. int è 64 bit su alcune architetture a 64 bit (non x64).

La norma non garantisce in realtà si ottiene 32 bit interi, solo che (u) int32_t può contenere uno.

Ora, se si sono a seconda int è la stessa dimensione di ptrdiff_t si può essere rotto.

Ricordate, C non garantisce che la macchina ancora è una macchina binario.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top