paulo1205
(usa Ubuntu)
Enviado em 14/11/2016 - 13:34h
Como o Enzo disse, tudo tem a ver com a arquitetura particular que você estiver usando.
Algumas arquiteturas obrigam todos os acessos em memória a estarem alinhados com o tamanho da palavra do processador (e.g. numa máquina com palavras de 32 bits, ou 4 bytes, todos os dados, independentemente de seus tamanhos individuais, devem estar dispostos em endereços que sejam múltiplos de 4 bytes). Outras permitem dispor dados de diferentes tamanhos em endereços que sejam múltiplos do tamanho daquele dado. Outras ainda permitem que qualquer dado possa estar em qualquer endereço, mas podem ter desempenho degradado se os dados estiverem com alinhamento diferente do esperado.
Nossos PCs até permitem o uso de dados desalinhados, com possível degradação de desempenho. No entanto, os compiladores de linguagens de alto nível preferem evitar o desempenho degradado, e para tanto forçam um realinhamento dos dados. Esse realinhamento é particularmente mais visível quando você colocar diversos membros de tamanhos diferentes dentro de uma estrutura.
A julgar pelos números que você apresentou, você deve estar usando uma arquitetura de 64 bits. Em arquiteturas assim, dados de até oito bytes podem ser lidos ou escritos em memória com uma única operação, desde que estejam devidamente alinhados num endereço que seja múltiplo de oito bytes. Se você os dispuser de outra forma, uma operação de leitura de 64 bits teria de ser feita em duas ou mais etapas (por exemplo: duas operações de 32 bits).
Uma dica para trabalhar com estruturas, de modo a não precisar de atributos como
packed (até porque esses atributos podem não ser portáveis entre diferentes compiladores) nem desperdiçar muita memória com
padding, é procurar dispor os membros da estrutura numa ordem que vá do maior para o menor.
Veja o seguinte exemplo:
#include <stddef.h>
#include <stdio.h>
struct dic { double d; int i; char c; };
struct dci { double d; char c; int i; };
struct idc { int i; double d; char c; };
struct icd { int i; char c; double d; };
struct cdi { char c; double d; int i; };
struct cid { char c; int i; double d; };
#define PRINT_INFO(x, a, b, c) \
printf( \
"sizeof(" #x ")=%zd\n" \
"\toffset of " #a ": %zd\n" \
"\toffset of " #b ": %zd\n" \
"\toffset of " #c ": %zd\n", \
sizeof(x), offsetof(x, a), offsetof(x, b), offsetof(x, c) \
)
int main(void){
printf(
"sizeof(char)=%zd; sizeof(int)=%zd; sizeof(double)=%zd\n",
sizeof(char), sizeof(int), sizeof(double)
);
PRINT_INFO(struct dic, d, i, c);
PRINT_INFO(struct dci, d, c, i);
PRINT_INFO(struct idc, i, d, c);
PRINT_INFO(struct icd, i, c, d);
PRINT_INFO(struct cdi, c, d, i);
PRINT_INFO(struct cid, c, i, d);
}
Compilando-o e rodando numa máquina de 64 bits (com opções default na compilação), eis a saída.
sizeof(char)=1; sizeof(int)=4; sizeof(double)=8
sizeof(struct dic)=16
offset of d: 0
offset of i: 8
offset of c: 12
sizeof(struct dci)=16
offset of d: 0
offset of c: 8
offset of i: 12
sizeof(struct idc)=24
offset of i: 0
offset of d: 8
offset of c: 16
sizeof(struct icd)=16
offset of i: 0
offset of c: 4
offset of d: 8
sizeof(struct cdi)=24
offset of c: 0
offset of d: 8
offset of i: 16
sizeof(struct cid)=16
offset of c: 0
offset of i: 4
offset of d: 8
A título de comparação, veja o que acontece quando eu compilo e rodo o mesmo programa em modo de 32 bits.
sizeof(char)=1; sizeof(int)=4; sizeof(double)=8
sizeof(struct dic)=16
offset of d: 0
offset of i: 8
offset of c: 12
sizeof(struct dci)=16
offset of d: 0
offset of c: 8
offset of i: 12
sizeof(struct idc)=16
offset of i: 0
offset of d: 4
offset of c: 12
sizeof(struct icd)=16
offset of i: 0
offset of c: 4
offset of d: 8
sizeof(struct cdi)=16
offset of c: 0
offset of d: 4
offset of i: 12
sizeof(struct cid)=16
offset of c: 0
offset of i: 4
offset of d: 8