2010-08-15 13 views
18

Cuando corro sólo el fragmento de códigoTamaño de la estructura con un char, un doble, un int y al

int *t; 
std::cout << sizeof(char) << std::endl; 
std::cout << sizeof(double) << std::endl; 
std::cout << sizeof(int) << std::endl; 
std::cout << sizeof(t)  << std::endl; 

me da un resultado como este:

1 
8 
4 
4 

Total: 17.

Pero cuando pruebo sizeof struct que contiene estos tipos de datos me da 24, y estoy confundido. ¿Cuáles son los 7 bytes adicionales?

Este es el código

#include <iostream> 
#include <stdio.h> 
struct struct_type{ 
    int i; 
    char ch; 
    int *p; 
    double d; 
} s; 

int main(){ 
    int *t; 
    //std::cout << sizeof(char) <<std::endl; 
    //std::cout << sizeof(double) <<std::endl; 
    //std::cout << sizeof(int) <<std::endl; 
    //std::cout << sizeof(t)  <<std::endl; 

    printf("s_type is %d byes long",sizeof(struct struct_type)); 

    return 0; 
} 

: editar

He actualizado mi código como este

#include <iostream> 
#include <stdio.h> 
struct struct_type{ 
    double d_attribute; 
    int i__attribute__(int(packed)); 
    int * p__attribute_(int(packed));; 
    char ch; 
} s; 

int main(){ 
    int *t; 
    //std::cout<<sizeof(char)<<std::endl; 
    //std::cout<<sizeof(double)<<std::endl; 
    //std::cout<<sizeof(int)<<std::endl; 
    //std::cout<<sizeof(t)<<std::endl; 

    printf("s_type is %d bytes long",sizeof(s)); 

    return 0; 
} 

y ahora me muestra 16 bytes. ¿Es bueno o he perdido algunos bytes importantes?

+0

Esto es C++, no C. – habnabit

Respuesta

49

Hay algunos bytes no utilizados entre algunos miembros a keep the alignments correct. Por ejemplo, un puntero por defecto reside en límites de 4 bytes para la eficiencia, es decir, su dirección debe ser un múltiplo de 4. Si la estructura contiene sólo un char y un puntero

struct { 
    char a; 
    void* b; 
}; 

continuación b no se puede utilizar el adderss # 1 - debe colocarse en el n. ° 4.

0 1 2 3 4 5 6 7 
+---+- - - - - -+---------------+ 
| a | (unused) | b    | 
+---+- - - - - -+---------------+ 

En su caso, el extra de 7 bytes proviene de 3 bytes por la alineación del int*, y 4 bytes por la alineación del double.

0 1 2 3 4 5 6 7 8 9 a b c d e f 
+---------------+---+- - - - - -+---------------+- - - - - - - -+ 
| i    |ch |   | p    |    | 
+---------------+---+- - - - - -+---------------+- - - - - - - -+ 
10 11 12 13 14 15 16 17 
+-------------------------------+ 
| d        | 
+-------------------------------+ 
+13

+1 para arte ASCII. –

+1

+1 para la representación diagramática. –

+0

... XD. Acabo de pasar unos 10 minutos tipeando la representación completa de su estructura de memoria; incluso incluyó una oferta para robarla si cree que mejoraría su respuesta, y la publico para descubrir que ya ha agregado la suya propia. Ah bueno. XD. – Stephen

9

... me da 24, y estoy confundido. ¿Cuáles son los 7 bytes adicionales?

Estos son los bytes de relleno insertados por el compilador. El relleno de la estructura de datos depende de la implementación.

De Wikipedia, Data structure alignment:

alineación de datos significa poner los datos a un desplazamiento igual a un múltiplo del tamaño de la palabra, lo que aumenta el rendimiento del sistema de memoria debido a la forma en que la CPU se encarga de la memoria. Para align datos, puede ser necesario insertar algunos bytes sin sentido entre el final de la última estructura de datos y el inicio de la siguiente, que es el relleno de la estructura de datos.

+0

Sí.Pero cuando supongo que alineación = 4 esperaría 20, no 24. –

+7

@Henk: 'double' en Windows x86 tiene alineación = 8. – kennytm

+0

@Kenny: cuando todos los miembros están alineados en 8, obtienes 32. Cuando solo el carácter es acolchado a 4: 20. –

0

El compilador puede alinear los miembros de la estructura con las direcciones para un acceso más rápido. p.ej. Límites de 32 bits. El estándar solo exige que los miembros del objeto se almacenen en el orden en que se declaran. Así que siempre asegúrese de usar sizeof y offsetof cuando necesite una posición exacta en la memoria.

0

Ver comp.lang.c FAQ list · Question 2.12:

¿Por qué mi compilador dejando agujeros en las estructuras, perder el espacio y la prevención de `` binario '' de E/S de archivos de datos externos? ¿Puedo desactivarlo o controlar la alineación de los campos de estructura?

0

El tamaño adicional proviene de la alineación de datos, es decir, los miembros están alineados a múltiplos de 4 u 8 bytes.

Tu compilador probablemente alinea int y punteros a múltiplos para 4 bytes y el doble a múltiplos para 8 bytes.

Si mueve el doble a una posición diferente dentro de la estructura, es posible que pueda reducir el tamaño de la estructura de 24 a 20 bytes. Pero depende del compilador.

0

También a veces se necesita la estructura para mantener el orden que requería. En estos casos, si está utilizando gcc, debe usar la instrucción __attribute__((packed)).

See also this para obtener más información.

+0

¿Hay alguna forma en C (o gcc) para especificar que un elemento de datos particular puede estar desalineado? Algunos procesadores simplemente no admiten el acceso directo a datos no alineados, por lo que una lectura o escritura de 32 bits debería dividirse en operaciones de bytes y cambios. El código para hacer eso sería un desperdicio si se aplica a cada referencia de puntero de 32 bits, pero sería útil poder especificar que ciertos punteros deben desreferenciarse con dicho código. – supercat

+0

@supercat: ¿por qué no simplemente usas memcpy? 'memcpy ((void *) & place, (const void *) & my_word, sizeof (my_word));' – Dacav

1

Tiene 24 bytes debido al relleno. La mayoría de los compiladores rellenan los datos a un múltiplo de su tamaño. Por lo tanto, una int 4-byte se rellena a un múltiplo de 4 bytes. Un doble de 8 bytes está acolchado a un múltiplo de 8 bytes. Por su estructura, esto significa:

struct struct_type{ 
    int i; // offset 0 (0*4) 
    char ch; // offset 4 (4*1) 
    char padding1[3]; 
    int *p; // offset 8 (2*4) 
    char padding1[4]; 
    double d; // offset 16 (2*8) 
}s; 

Usted puede optimizar su estructura como esa:

struct struct_type{ 
    double d; 
    int i; 
    int *p; 
    char ch; 
}s; 

sizeof (s) == 17 en la mayoría de los compiladores (20 en algunos otros)

+0

Incluso después de reordenar el tamaño de, debe seguir siendo 24 porque el 'double' tiene una alineación de 8 bytes (en lugar de 4). – kennytm

0

$ 9.2/12 estados: "Los miembros de datos no estáticos de una clase (no sindicalizada) declarados sin un intermediario de acceso intermedio se asignan para que los miembros posteriores tengan direcciones más altas dentro de un objeto de clase. -specificador no especificado (1 1.1). Los requisitos de alineación de implementación pueden causar que dos miembros adyacentes no se asignen inmediatamente uno después del otro; entonces podría requisitos de espacio para la administración de funciones virtuales (10.3) y clases base virtuales (10.1). "

Así que al igual que el sizeof (doble) y sizeof (int), los desplazamientos a los que se alinearían los miembros de la estructura sin especificar, excepto que los miembros que se declaran posteriormente están en direcciones superiores.

7

Para ampliar ligeramente la excelente respuesta de KennyDM (Kenny, roba esto para complementar tu respuesta si quieres), esta es probablemente la estructura de tu memoria una vez que el compilador ha alineado todas las variables:

0 1 2 3 4 5 6 7 
+-------------------+----+-----------+ 
| i     | ch | (unused) | 
+-------------------+----+-----------+ 

    8 9 10 11 12 13 14 15 
+-------------------+----------------+ 
| p     | (unused)  | 
+-------------------+----------------+ 

16 17 18 19 20 21 22 23 
+------------------------------------+ 
| d         | 
+------------------------------------+ 

Entonces, debido a la brecha de 3 bytes entre "ch" y "p", y la brecha de 4 bytes entre "p" y "d", obtienes un relleno de 7 bytes para tu estructura, por lo tanto, el tamaño de 24 bytes. Como el double de su entorno tiene una alineación de 8 bytes (es decir, debe residir en su propio bloque de 8 bytes, como puede ver arriba), el total struct también estará alineado en 8 bytes, por lo que incluso se reordenará las variables no alterarán el tamaño desde 24 bytes.

+0

Dado que el 'doble' tiene una alineación de 8 bytes (de lo contrario, la estructura habría sido de 20 bytes), habrá un relleno de 7 bytes después de' ch' incluso después de la reorganización. – kennytm

+0

Ah, entonces ¿el 'doble' que tiene una alineación de 8 bytes hace que toda la 'estructura' lo haga? No lo sabía, ¡gracias! – Stephen

+1

, sí, en general, toda la estructura debe tener la misma alineación que el miembro "más alineado". Imagine que si tiene una matriz de estas estructuras, cada una de ellas debe alinear correctamente su miembro "doble", lo cual solo es posible si la estructura tiene la misma alineación que el miembro 'doble'. – jalf

Cuestiones relacionadas