Newsgroup: it.comp.lang.c++
Titolo: Sizeof(struct)

ma perchè una struct occupa 7-8 bytes in piú del sizeof() di tutto il
suo contenuto? Forse perchè è vista a tutti gli effetti come una
classe? E se volessi risparmiare memoria come potrei agire?


Please? di solito e' il contrario... il sizeof(struct ..) torna
una valore che e' apparentemente maggiore della struttura
come definita.
Questo perche' puo' essere che il compilatore allinei
le strutture al size che gli e' piu' comodo, aggiungendo
dei pad tra i vari membri.
Puo' essere che se mischi tipi diversi, ad esempio char,
int e long, i tipi piu' lunghi siano allineati a valori
multipli del loro size, per massimizzare le performance
di accesso in memoria.
Ci sono solitamente delle direttive nel compilatore
per forzare l'allineamento dei campi delle strutture
in modo esatto, ad esempio #pragma pack(1) funziona
sia per Microsoft che per gcc.
se definisci una struttura del tipo seguente
su una macchina con allineamento naturale a 32 bit
avrai probabilmente un sizeof pari a 8 invece che 5
perche' al campo pluto vengono appesi dei byte spare
per allineare il prossimo campo:
struct pippo{
    char pluto;    // <-- 1 byte
                   // <-- 3 byte 'pad'
    long pp;       // <---4 bytes
}p;
se provi a definire prima della struttura:
#pragma pack(1)
....
#pragma pack()
dovresti trovarti con sizeof = 5.
Attenzione pero' che esistono processori che non
possono eseguire accessi a variabili maggiori di
8bit in modo non allineato: in questo caso un accesso
alla variabile pp forzatamente impaccata causera'
un comportamento anomalo. In questi casi bisogna
scrivere delle funzioni dipendenti dall' hardware
per accere alle variabili sempre a bytes....
Aa.

Il 31/03/2011 8.30, Darkbyte ha scritto:

una struct *E'* una classe.
in c++ l'unica differenza è che per default i membri di struct hanno 
visibilità public, mentre i membri di class hanno visibilità private.
Il motivo per cui sizeof(struct) >= somma(sizeof(membri)) è che il c++ 
non specifica come deve essere gestito l'allineamento dei membri in 
memoria. Ogni compilatore e ogni piattaforma fa un po quello che gli 
pare. Se vuoi approfondire le parole chiave sono "packing" e "alignment".
Vedi ad es.
http://en.wikipedia.org/wiki/Data_structure_alignment
e per piattaforma MS:
http://msdn.microsoft.com/en-us/library/2e70t5y1(v=VS.100).aspx
HTH


Ok, grazie ad entrambi. In effetti intanto avevo letto qualcosa in
merito cercando su Google.
Quindi il fatto di avere sizeof(struct) >= somma(sizeof(membri)) è per
allineare correttamente i dati.
Ora però mi vengono in mente due domande:
1) Posso sapere quanto spazio mi viene realmente allocato da una
chiamata a new?
Prendendo in esame una struttura di questo tipo:
struct type_t
{
  long int l;
  char c;
};
e sapendo che il mio compilatore sulla mia macchina vede sizeof(long
int) = 8 e sizeof(char) = 1, dovrei avere una struttura che occupa 9
bytes ma probabilmente in realtà lo spazio allocato salirà a 16 bytes.
Allora (domanda da 1.000.000 di dollari), se alloco dinamicamente
tramite new, lo spazio allocato quanto sarà grande? 9 bytes? 16? O
anche di più?
Come posso sapere quanto spazio mi ha allocato new?
E questo porta alla domanda 2) Se alloco n elementi dello stesso tipo,
c'è probabilità che lo spazio necessario per padding/allineamento
venga aggiunto solo al totale della memoria richiesta piuttosto che
per i singoli elementi?

 per i singoli elementi?
Lo spazio allocato è 16 * il numero di elementi dell'array.

 per i singoli elementi?
Dipende sempre da come il compilatore configura l' allimeamento
e come lo gestisce.
Comunque l' allineamento a membri sottomultipli pari di quello 
predefinito in genere non occupa piu' spazio, se l'architettura
del processore lo permette, purche' lo spazio totale della struttura
sia un multiplo intero dell' allineamento definito a compile time.
Puoi imporre al compilatore di allineare i campi *esattamentte*
usano l' allineamento al byte , ad esempio con #pragma pack(1)
in questo caso la memoria allocata staticamente e' esattamente
quella che ti aspetti.
Se l' allineamento della struttura è a 8 bytes, lo spazio occupato
sara' un multiplo di 8 etc...
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
// CPU x86 32 bit, Gcc4.4.3
#include <cstdlib>
#include <iostream>
// 4 byte packet
#pragma pack(4)
typedef struct {
	char	d8;	 // 1
	short	d16;	 // 2
	long	d32;     // 4
	long long d64;   // 8
	short	d161;    // 2
	long long d641;  // 8
}ST1_T;                  //=25+3pad=28
#pragma pack()
// 8 byte packet
#pragma pack(8)
typedef struct {
	char	d8;	 // 1
	short	d16;	 // 2
	long	d32;     // 4
	long long d64;   // 8
	short	d161;    // 2
	long long d641;  // 8
}ST2_T;                  //=25+9pad=32
#pragma pack()
#pragma pack(1)
// allineamento al byte
typedef struct {
	char	d8;	 // 1
	short	d16;	 // 2
	long	d32;     // 4
	long long d64;   // 8
	short	d161;    // 2
	long long d641;  // 8
}ST3_T;                  // = 25
#pragma pack()
int main(int argc, char *argv[]) {
  int		n,j,k;
  n= sizeof(ST1_T);
  j= sizeof(ST2_T);
  k= sizeof(ST3_T);
  std::cout << "CC test " << n << "." << j <<"." << k << std::endl;
  return EXIT_SUCCESS;
}
Stampa: 28.32.25
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>


Ok, ora sono riuscito a definire una struttura node_t come packed.
Il sizeof() mi restituisce la dimensione che mi aspetterei, senza
allineamento. Quindi 9 bytes invece di 16.
Se faccio new node_t[100] mi vengono allocati 900 bytes, giusto?
La questione è fondamentale perchè ho costruito una classe BTree che
può anche dover allocare milioni di informazioni. Risparmiare quei
bytes significa risparmiare molto... Ecco perchè chiedevo se ci fosse
un modo per verificare l'effettiva quantità di memoria allocata da new.

> per i singoli elementi?
normalmente i singoli elementi non vengono compattati ad 
indirizzi frazionari della loro dimensione. Cioè il padding 
dovrebbe essere replicato enne volte. Non credo sia 
inevitabile, ma semplicemente può essere compilato per una 
velocità di esecuzione (indirizzamento più semplice) maggiore.
Forse però ci sono dei "pragma pack" o direttive simili per 
forzare il layout di memoria (così come i campi di bit 
stessi dopotutto, di cui si può controllare ogni aspetto). 
Sono più lenti, ma potrebbe essere necessario usarli con 
protocolli di comunicazione hardware di livello basso, o 
anche la scrittura di pezzi verso porte logiche di I/O di 
dispositivi mappati in memoria, che si aspettano un layout 
bit a bit esattamente determinato, e spesso compatto.
Probably ogni compilatore implementa quelle meta-direttive 
come gli pare
ciao
Soviet


 sara' un multiplo di 8 etc...
scusatemi, non avevo letto questa ottima e dettagliata 
risposta ... cancellate pure la mia :-)
riciao
Soviet
