2015-12-31 32 views
9

Sto leggendo questo post che è legato alla char e byte, e incontrato le seguenti parole:Come capire "C++ consente sizeof (char *)! = Sizeof (int *)"?

Un int* potrebbe ancora essere implementato come un unico indicatore di hardware, dal momento che C++ permette sizeof(char*) != sizeof(int*).

Come capire 'C++ consente sizeof(char*) != sizeof(int*)'?

+5

Cosa * non * capisci a riguardo? – EJP

+2

@EJP: Non dovrebbero essere uguali? –

+2

@Nan: Puoi spiegare cosa ti porta a pensare che sarebbero? Ciò aiuterebbe a chiarire qualsiasi idea errata ti stia conducendo a tale conclusione. – icktoofay

risposta

2

In breve, lo standard non lo garantisce, il risultato è definito dall'implementazione.

Dal principio circa sizeof ($ 5.3.3/1 Sizeof [expr.sizeof])

L'operatore sizeof restituisce il numero di byte nella rappresentazione dell'oggetto del suo operando.

e puntatore è di tipo composto ($ 3.9.2/1.3 tipi composti [basic.compound])

puntatori per nulla o oggetti o funzioni (compresi i membri statici di classi) di un dato tipo , 8.3.1;

e ($ 3.9.2/3 tipi composti [basic.compound])

La rappresentazione valore di tipi di puntatore è implementazione definita.

anche se ($ 3.9.2/3 tipi composti [basic.compound])

puntatori a layout tipi compatibili devono avere lo stesso valore rappresentanza e di allineamento requisiti (3.11).

ma char e int non hanno bisogno di avere lo stesso valore di rappresentazione. L'starndard dice soltanto ($ 3.9.1/2 tipi fondamentali [basic.fundamental])

Ci sono cinque tipi standard firmati intero: “signed char”, “corto int”, “int”, “long int "E" long long int ". In questo elenco, ciascun tipo fornisce almeno lo stesso spazio di archiviazione di quelli che lo precedono nell'elenco.

e ($ 3.9.1/3 tipi fondamentali [basic.fundamental]) ecc

ogni tipo intero con segno ha la stessa rappresentazione dell'oggetto come corrispondente tipo intero senza segno.

1

Lo standard dice:

5.3.3 Sizeof
sizeof (char), sizeof (char firmato) e sizeof (unsigned char) sono 1. Il risultato di sizeof applicato a qualsiasi altro tipo di base ( 3.9.1) è definito dall'implementazione.

Poiché i puntatori sono "tipi composti" e lo standard non fa riferimento alla coerenza delle dimensioni dei byte tra i puntatori, gli autori del compilatore sono liberi di fare ciò che desiderano.

+2

Ha detto 'sizeof (char *)', non 'char'. Sta chiedendo perché due indicatori potrebbero non avere la stessa dimensione. –

+4

@NicolBolas Che rientra in "qualsiasi altro tipo fondamentale". Un puntatore a un tipo fondamentale è un tipo fondamentale a meno che non mi sbagli di grosso. – EJP

+4

@EJP: no. I puntatori non sono tipi fondamentali. Sono tipi composti. –

3

Ci sono (o erano) macchine che potevano riguardare solo intere "parole", dove una parola era abbastanza grande da contenere diversi caratteri. Ad esempio, il PDP-6/10 aveva una dimensione word di 36 bit. Su una macchina del genere, è possibile implementare byte da 9 bit e rappresentare un puntatore di byte come combinazione di un puntatore di parole e un indice di bit all'interno della parola. Un'implementazione ingenua richiederebbe due parole per tale puntatore, anche se un puntatore intero sarebbe solo un puntatore di parola, che occupa una singola parola.

(Il vero PDP-6/10 consentito per caratteri di dimensioni minori - le codifiche a 6 e 7 bit erano comuni, a seconda del caso d'uso - e poiché un puntatore non poteva occupare una parola intera, era possibile creare un puntatore di caratteri che includa l'offset dei bit e l'indirizzo di parola all'interno di una singola parola, ma un'architettura simile in questi giorni non avrebbe la restrizione draconiana sullo spazio degli indirizzi, quindi non funzionerebbe più.)

2

itsnotmyrealname e rici toccano i driver hardware per questo, ma ho pensato che potrebbe aiutare a piedi attraverso il più semplice possibile scenario che porta a diverse dimensioni puntatore ...

Immaginate una CPU che può indirizzare parole di memoria a 32 bit e che il tipo C++ int deve anch'esso avere una larghezza di 32 bit.

Questa CPU ipotetica indirizza parole specifiche utilizzando una numerazione: 0 per la prima parola (byte 0-3), 1 per il secondo (byte 4-7) e così via. int*{0} è quindi la vostra prima parola in memoria (assumendo che non bizzarre nullptr imbrogli richiedono altro), int*{1} la seconda ecc ..

Cosa dovrebbe fare il compilatore fare per sostenere 8 bit char tipi? Potrebbe essere necessario implementare il supporto char* utilizzando un int* per identificare la parola in memoria, ma occorre ancora due bit in più per memorizzare 0, 1, 2 o 3 per dire quale dei byte in quella parola viene puntato. Sarebbe effettivamente bisogno di generare codice macchina fino a un programma C++ potrebbe se si utilizza ...

struct __char_ptr 
{ 
    unsigned* p_; 
    unsigned byte_ : 2; 
    char get() const { return (*p_ & (0xFF << (8*byte_)) >> 8*byte_; } 
    void set(char c) { *p_ &= ~(0xFF << (8*byte_)); *p |= c << 8*byte_; } 
}; 

Su un tale sistema - sizeof(__char_ptr) > sizeof(int*). La flessibilità dello standard C++ consente implementazioni C++ conformi per (e portabilità del codice da/a) sistemi bizzarri con questo o simili problemi.

2

Questo è anche il motivo per cui we can not forward declare enums without providing the underlying size nella mia risposta fornisco diversi riferimenti che coprono il motivo per cui è così.

in questo comp.lang.c++ discussion: GCC and forward declaration of enum:

[...] Mentre la maggior parte degli architetture potrebbe non essere un problema, in alcune architetture il puntatore avrà un formato differente, nel caso è un puntatore char . [...]

e possiamo trovare da questa voce C-Faq Seriously, have any actual machines really used nonzero null pointers, or different representations for pointers to different types? si dice:

più vecchi, macchine Prime parola indirizzata erano anche noti per richiedere i puntatori di byte più grandi (char * s ') di parola puntatori (int * 's). [...] Alcune macchine Cray a 64 bit rappresentano int * nei 48 bit inferiori di una parola; char * utilizza inoltre alcuni dei 16 bit superiori per indicare un indirizzo di byte all'interno di una parola. [...]

e inoltre:

[...] La serie Eclipse MV da dati generali ha tre formati supportati architettonicamente puntatore (Word, byte, e puntatori bit), di cui due che vengono utilizzati dai compilatori C: puntatori di byte per char * e void * e puntatori di parola per tutto il resto. Per ragioni storiche durante l'evoluzione della linea MV a 32 bit dalla linea Nova a 16 bit, i puntatori di parola e i puntatori di byte avevano i bit di offset, indiretto e protezione dell'anello in diversi punti della parola. Il passaggio di un formato puntatore non corrispondente a una funzione ha provocato errori di protezione. Alla fine, il compilatore MV C ha aggiunto molte opzioni di compatibilità per provare a gestire il codice che presentava errori di mancata corrispondenza del tipo di puntatore. [...] La vecchia serie HP 3000 utilizza un diverso schema di indirizzamento per gli indirizzi di byte rispetto agli indirizzi di parole; come molte delle macchine sopra di esso, quindi, utilizza diverse rappresentazioni per i puntatori char * e void * rispetto ad altri puntatori. [...]