La dimensione di (qualche puntatore) è sempre uguale a quattro?


227

Ad esempio: sizeof(char*)restituisce 4. Come fa int*, long long*tutto ciò che ho provato. Ci sono delle eccezioni a questo?


51
Perché annotarlo? Buona domanda per qualsiasi principiante.
Martin York,

2
Ho il sospetto che un'altra domanda si nasconda in questa: "Qual è la dimensione di?" o potrebbe essere "Perché è sizeof <qualsiasi puntatore> == 4? Cosa c'è di così speciale in 4?". Ho ragione?

2
Bene, dipende dalla tua piattaforma. La maggior parte delle implementazioni condividono le stesse dimensioni per ogni tipo di puntatore su una piattaforma specifica.
phoeagon,

Risposte:


194

La garanzia che ottieni è quella sizeof(char) == 1. Non ci sono altre garanzie, inclusa quella sizeof(int *) == sizeof(double *).

In pratica, i puntatori avranno la dimensione 2 su un sistema a 16 bit (se riesci a trovarne uno), 4 su un sistema a 32 bit e 8 su un sistema a 64 bit, ma non c'è nulla da guadagnare facendo affidamento su un dato taglia.


96
E 3 byte su un sistema a 24 bit. Sì, ho lavorato su uno. Benvenuti nel mondo dei dispositivi integrati.
dwj

30
Ho lavorato anche su sistemi a 16 bit con puntatori a 20 bit. Dovrei andare a vedere quale dimensione restituisce in quel caso ...
Giudice Maygarden il

5
@monjardin: IIRC, l'8086 era così. C'era un indirizzo a 16 bit e un registro di segmenti a 4 bit. Credo che un normale puntatore "NEAR" fosse 16 bit e un puntatore dichiarato "FAR" fosse maggiore, probabilmente 24, anche se non ne sono sicuro.
rmeador,

18
un'altra garanzia è che sizeof (char *) == sizeof (void *), perché devono avere le stesse rappresentazioni (oggetto [dimensione] e valore [insieme di bit rilevanti per il loro valore] rappresentazione)
Johannes Schaub - litb

7
Poiché la domanda richiede eccezioni, è opportuno notare che i puntatori a funzioni membro non statiche hanno spesso dimensioni diverse rispetto ai normali puntatori e variano anche in base alla piattaforma, al tipo, ecc. Oltre a quello +1.
Giovanni 5342,

36

Anche su una semplice piattaforma x86 a 32 bit, puoi ottenere una varietà di dimensioni del puntatore, prova questo per un esempio:

struct A {};

struct B : virtual public A {};

struct C {};

struct D : public A, public C {};

int main()
{
    cout << "A:" << sizeof(void (A::*)()) << endl;
    cout << "B:" << sizeof(void (B::*)()) << endl;
    cout << "D:" << sizeof(void (D::*)()) << endl;
}

In Visual C ++ 2008, ottengo 4, 12 e 8 per le dimensioni della funzione pointer-to-member.

Raymond Chen ne ha parlato qui .


4
I puntatori alle funzioni dei membri sono un vero dolore. È un peccato che non tutti i compilatori lo faccia come il compilatore Digital Mars C ++, che restituisce 4 in tutti i casi.
dalle

gcc 4.72 stampa tutto 8 ... Non è definito nello standard c ++?
Gob00st

2
@ Gob00st: l'unica cosa definita è che char è 1. Altri tipi possono essere di qualsiasi dimensione sia rilevante per quel compilatore. Non è richiesta la coerenza tra questi tipi di puntatori.
Eclipse,

ok grazie. Quindi non c'è da stupirsi che gcc e VC abbiano un'implementazione diversa.
Gob00st

5
@Eclipse sì, c'è: char <= short <= int <= long <= long long
Cole Johnson

30

Solo un'altra eccezione all'elenco già pubblicato. Su piattaforme a 32 bit, i puntatori possono richiedere 6, non 4 byte:

#include <stdio.h>
#include <stdlib.h>

int main() {
    char far* ptr; // note that this is a far pointer
    printf( "%d\n", sizeof( ptr));
    return EXIT_SUCCESS;
}

Se compili questo programma con Open Watcom ed eseguilo, otterrai 6, poiché i puntatori lontani che supporta sono costituiti da valori offset di 32 bit e segmenti di 16 bit


5
Non un segmento, ma un selettore: non fa parte dell'indirizzo di memoria, ma una voce di indice in LDT o GDT e ha alcuni flag di accesso
Roee Shenberg,

1
Perché ci sono segmenti e offset in x86 mentre lo spazio degli indirizzi è piatto?
phuclv,

@ LưuVĩnhPhúc Perché consente di risparmiare spazio per il caso molto comune di puntatori vicini, che può essere codificato più breve.
Christopher Creutzig

1
@ChristopherCreutzig significa che i segmenti vengono utilizzati per estendere lo spazio degli indirizzi come PAE?
phuclv

@ LưuVĩnhPhúc È da tanto tempo che non eseguo il montaggio su qualcosa a 32 bit. La parte che mi sembra di ricordare è che puoi risparmiare spazio per i puntatori che puntano vicino al codice che hai. Inoltre, non tutte le architetture a 32 bit - certamente non tutte basate su x86 - utilizzano un modello di memoria piatta. Vedi, ad esempio, tenouk.com/Bufferoverflowc/Bufferoverflow1a.html per qualche altra discussione in merito, anche se, come ho detto, è passato un po 'di tempo e non posso garantire nulla.
Christopher Creutzig,

24

se si sta compilando per un computer a 64 bit, potrebbe essere 8.


2
Mentre questo è solitamente il caso, non è necessariamente vero. Ad esempio, se stai compilando su una macchina a 64 bit in cui la dimensione della parola è 64 bit, allora sizeof (char *) sarà probabilmente 1. Per non parlare dei tipi di puntatore più esotici in macchine anche comuni, come Eclipse e dmityugov scrivere.
Kaz Dragon,

@KazDragon, sizeof(char*)==1? Sei sicuro? Non intendi size(char)==1?
Aaron McDaid il

3
@AaronMcDaid In effetti volevo dire sizeof (char *). sizeof (char) è sempre 1. Ma se la tua parola macchina è a 64 bit e il tuo ambiente di sviluppo è implementato in modo tale che CHAR_BITS = 64, allora è possibile che un puntatore si adatti allo stesso spazio di un carattere e quindi anche essere 1.
Kaz Dragon,


1
@KazDragon Sto costruendo (molto lentamente, quando non procrastina) una macchina con parole a 16 bit e senza indirizzamento byte. Anche se non può eseguire C comunque.
user253751

17

Tecnicamente parlando, lo standard C garantisce solo che sizeof (char) == 1, e il resto dipende dall'implementazione. Ma sulle moderne architetture x86 (ad es. Chip Intel / AMD) è abbastanza prevedibile.

Probabilmente hai sentito i processori descritti come 16-bit, 32-bit, 64-bit, ecc. Questo di solito significa che il processore usa N-bit per numeri interi. Poiché i puntatori memorizzano gli indirizzi di memoria e gli indirizzi di memoria sono numeri interi, ciò indica effettivamente quanti bit verranno utilizzati per i puntatori. La dimensione di solito viene misurata in byte, quindi il codice compilato per i processori a 32 bit riporterà la dimensione dei puntatori a 4 (32 bit / 8 bit per byte) e il codice per i processori a 64 bit riporterà la dimensione dei puntatori a 8 (64 bit / 8 bit per byte). Ecco da dove viene la limitazione di 4 GB di RAM per processori a 32 bit: se ogni indirizzo di memoria corrisponde a un byte, per indirizzare più memoria sono necessari numeri interi superiori a 32 bit.


"Probabilmente hai sentito i processori descritti come 16-bit, 32-bit, 64-bit, ecc. Questo di solito significa che il processore usa N-bit per i numeri interi." -> Sto avendo una macchina a 64 bit ma la dimensione di (int) è di 4 byte. Se la tua affermazione è vera, come potrebbe essere possibile ?!
Sangeeth Saravanaraj,

6
@SangeethSaravanaraj: per la compatibilità all'indietro con il codice a 32 bit, hanno deciso di avere int che continui a essere di 4 byte e richiedono di optare per l'utilizzo del tipo a 8 byte specificando "long". long è in realtà la dimensione della parola nativa su x86-64. Un modo per vederlo è che in genere i compilatori riempiono le tue strutture per renderle allineate alle parole (anche se potrebbero esserci architetture in cui la dimensione e l'allineamento delle parole non sono correlati), quindi se crei una struttura con un int (32 bit), e chiama sizeof () su di esso, se torni 8 sai che li sta riempiendo di parole a 64 bit.
Joseph Garvin,

@SangeethSaravanaraj: Nota che teoricamente la dimensione della parola nativa della CPU e ciò che il compilatore decide 'int' può essere arbitrariamente diversa, è solo la convenzione che 'int' sia la dimensione della parola nativa prima che arrivasse x86-64, dove è lungo per facilitare la retrocompatibilità.
Joseph Garvin,

Grazie per la spiegazione! :)
Sangeeth Saravanaraj,

7

La dimensione del puntatore dipende fondamentalmente dall'architettura del sistema in cui è implementato. Ad esempio, la dimensione di un puntatore a 32 bit è 4 byte (32 bit) e 8 byte (64 bit) in macchine a 64 bit. I tipi di bit in una macchina non sono altro che indirizzo di memoria, che può avere. Le macchine a 32 bit possono avere 2^32lo spazio degli indirizzi e le macchine a 64 bit possono avere gli 2^64spazi degli indirizzi. Quindi un puntatore (variabile che punta a una posizione di memoria) dovrebbe essere in grado di puntare a qualsiasi indirizzo di memoria ( 2^32 for 32 bit and 2^64 for 64 bit) che detiene una macchina.

Per questo motivo vediamo che la dimensione di un puntatore è di 4 byte in una macchina a 32 bit e 8 byte in una macchina a 64 bit.


6

Oltre alle differenze di 16/32/64 bit possono verificarsi anche cose più strane.

Ci sono state macchine in cui sizeof (int *) avrà un valore, probabilmente 4 ma in cui sizeof (char *) è più grande. Le macchine che indirizzano naturalmente le parole anziché i byte devono "aumentare" i puntatori di caratteri per specificare quale porzione della parola vuoi veramente per implementare correttamente lo standard C / C ++.

Questo è ora molto insolito poiché i progettisti hardware hanno imparato il valore dell'indirizzamento dei byte.


4
Il compilatore C per macchine vettoriali Cray, come il T90, fa qualcosa di simile. Gli indirizzi hardware sono 8 byte e puntano a parole di 8 byte. void*e char*sono gestiti nel software e sono aumentati con un offset di 3 bit all'interno della parola - ma poiché in realtà non esiste uno spazio di indirizzi a 64 bit, l'offset è memorizzato nei 3 bit di ordine superiore del 64-bit parola. Quindi char*e int*hanno le stesse dimensioni, ma hanno rappresentazioni interne diverse - e il codice che presuppone che i puntatori siano "realmente" solo i numeri interi possono fallire male.
Keith Thompson,

5

I puntatori a 8 e 16 bit sono utilizzati nella maggior parte dei microcontrollori a basso profilo. Ciò significa che ogni lavatrice, micro, frigorifero, TV più vecchie e persino automobili.

Si potrebbe dire che non hanno nulla a che fare con la programmazione nel mondo reale. Ma ecco un esempio reale: Arduino con 1-2-4k di RAM (a seconda del chip) con puntatori a 2 byte.

È recente, economico, accessibile a tutti e vale la pena codificarlo.


4

Oltre a ciò che la gente ha detto sui sistemi a 64 bit (o qualsiasi altra cosa), esistono altri tipi di puntatori oltre al puntatore all'oggetto.

Un puntatore al membro può avere quasi tutte le dimensioni, a seconda di come sono implementate dal compilatore: non sono necessariamente tutte uguali. Prova un puntatore a membro di una classe POD, quindi un puntatore a membro ereditato da una delle classi di base di una classe con più basi. Che divertimento.


3

Da quello che ricordo, si basa sulla dimensione di un indirizzo di memoria. Quindi su un sistema con uno schema di indirizzi a 32 bit, sizeof restituirà 4, dato che sono 4 byte.


4
Non esiste tale requisito. Non è nemmeno richiesto che sizeof (unsigned int) == sizeof (sign int). La dimensione di un puntatore a un int sarà sempre, per definizione, dimensione di (int *), dimensione di un carattere (char *) ecc. Affidarsi a qualsiasi altra ipotesi è una cattiva idea per la portabilità.
Mihai Limbășan,

Ah, vedo adesso. Grazie per le informazioni.
Will Mc

1
Potrebbe comunque restituire 2, se CHAR_BIT è 16. sizeof () conta nel numero di caratteri, non in ottetti.
MSalters,

5
@Mihai: in C ++ sizeof (unsigned int) == sizeof (signed int), questo requisito si trova in 3.9.1 / 3. "Per ogni dello standard intero con segno tipi, esiste una corrispondente (ma differente) tipo intero senza segno serie: unsigned char, unsigned short int, unsigned int, unsigned long int, e unsigned long long int, ognuno dei quali occupa la stessa quantità di stoccaggio ed ha gli stessi requisiti di allineamento della corrispondente intero con segno tipo "
Ben Voigt,

3

In generale, sizeof (praticamente qualsiasi cosa) cambierà quando si compila su piattaforme diverse. Su una piattaforma a 32 bit, i puntatori hanno sempre le stesse dimensioni. Su altre piattaforme (64 bit è l'esempio ovvio) questo può cambiare.


3

No, la dimensione di un puntatore può variare a seconda dell'architettura. Vi sono numerose eccezioni.


3

La dimensione del puntatore e int è di 2 byte nel compilatore Turbo C sulla macchina Windows a 32 bit.

Quindi la dimensione del puntatore è specifica del compilatore. Ma generalmente la maggior parte dei compilatori sono implementati per supportare variabili di puntatore a 4 byte in 32 bit e variabili di puntatore da 8 byte in computer a 64 bit).

Quindi la dimensione del puntatore non è la stessa in tutte le macchine.


2

Il motivo per cui la dimensione del puntatore è di 4 byte è perché si sta compilando per un'architettura a 32 bit. Come ha sottolineato FryGuy, su un'architettura a 64 bit ne vedresti 8.


2

In Win64 (Cygwin GCC 5.4) , vediamo l'esempio seguente:

Innanzitutto, prova la seguente struttura:

struct list_node{
    int a;
    list_node* prev;
    list_node* next;
};

struct test_struc{
    char a, b;
};

Il codice di prova è di seguito:

std::cout<<"sizeof(int):            "<<sizeof(int)<<std::endl;
std::cout<<"sizeof(int*):           "<<sizeof(int*)<<std::endl;
std::cout<<std::endl;

std::cout<<"sizeof(double):         "<<sizeof(double)<<std::endl;
std::cout<<"sizeof(double*):        "<<sizeof(double*)<<std::endl;
std::cout<<std::endl;

std::cout<<"sizeof(list_node):      "<<sizeof(list_node)<<std::endl;
std::cout<<"sizeof(list_node*):     "<<sizeof(list_node*)<<std::endl;
std::cout<<std::endl;

std::cout<<"sizeof(test_struc):     "<<sizeof(test_struc)<<std::endl;
std::cout<<"sizeof(test_struc*):    "<<sizeof(test_struc*)<<std::endl;    

L'output è inferiore:

sizeof(int):            4
sizeof(int*):           8

sizeof(double):         8
sizeof(double*):        8

sizeof(list_node):      24
sizeof(list_node*):     8

sizeof(test_struc):     2
sizeof(test_struc*):    8

Puoi vederlo a 64 bit, sizeof(pointer)è 8.


1

Un puntatore è solo un contenitore per un indirizzo. Su una macchina a 32 bit, l'intervallo di indirizzi è di 32 bit, quindi un puntatore sarà sempre di 4 byte. Su una macchina a 64 bit, se si dispone di un intervallo di indirizzi di 64 bit, un puntatore sarà di 8 byte.


1
Su una macchina a 32 bit con byte a 32 bit, sizeof (char *) potrebbe essere 1.
Robert Gamble

"... con byte a 32 bit". Non sapevo che esistessero cose del genere ... immagino.
Ed S.

1
Su un'anatra a 32 bit, sizeof (char *) restituisce PI
Adriano Varoli Piazza

0

Solo per completezza e interesse storico, nel mondo a 64 bit c'erano diverse convenzioni di piattaforme sulle dimensioni di tipi lunghi e lunghi, chiamati LLP64 e LP64, principalmente tra sistemi di tipo Unix e Windows. Un vecchio standard chiamato ILP64 rendeva anche int = 64-bit di larghezza.

Microsoft ha mantenuto LLP64 dove longlong = 64 bit di larghezza, ma è rimasto a lungo a 32, per facilitare il porting.

Type           ILP64   LP64   LLP64
char              8      8       8
short            16     16      16
int              64     32      32
long             64     64      32
long long        64     64      64
pointer          64     64      64

Fonte: https://stackoverflow.com/a/384672/48026

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.