c++ - ejemplos - funciones con estructuras en c
TamaƱo de la estructura con un char, un doble, un int y en (9)
Esta pregunta ya tiene una respuesta aquí:
Cuando corro solo el fragmento de código
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 codigo
#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?
... me da 24, y estoy confundido. ¿Cuáles son los 7 bytes adicionales?
Estos son bytes de relleno insertados por el compilador. El relleno de la estructura de datos depende de la implementación.
Desde Wikipedia, alineación de la estructura de datos :
La alineación de los datos significa colocar los datos en un desplazamiento de memoria igual a algunos múltiplos del tamaño de la palabra, lo que aumenta el rendimiento del sistema debido a la forma en que la CPU maneja la memoria. Para align los datos, puede ser necesario insertar algunos bytes sin sentido entre el final de la última estructura de datos y el comienzo de la siguiente, que es el relleno de la estructura de datos.
$ 9.2 / 12 estados - "Los miembros de datos no estáticos de una clase (no sindicalizados) declarados sin un especificador de acceso intermedio se asignan de modo que los miembros posteriores tengan direcciones más altas dentro de un objeto de clase. El orden de asignación de los miembros de datos no estáticos separados por un acceso -el especificador no está especificado (11.1). Los requisitos de alineación de la implementación pueden hacer que dos miembros adyacentes no se asignen inmediatamente uno después del otro, por lo que los requisitos para el espacio para administrar funciones virtuales (10.3) y clases base virtuales (10.1) ".
Así que, al igual que el tamaño de (doble) y el tamaño de (int), las compensaciones en las que se alinearían los miembros de la estructura no están especificadas, excepto que los miembros que se declaran más adelante están en las direcciones más altas.
El compilador puede alinear a los miembros de la estructura con las direcciones para un acceso más rápido. por ejemplo, los límites de 32 bits. La norma solo exige que los miembros del objeto se almacenen en el orden en que se declaran. Por lo tanto, asegúrese siempre de usar sizeof
y offsetof
cuando necesite una posición exacta en la memoria.
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.
Su 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.
Es de 24 bytes debido al relleno. La mayoría de los compiladores rellenan datos a un múltiplo de su tamaño. Por lo tanto, un int de 4 bytes se rellena a un múltiplo de 4 bytes. Un doble de 8 bytes se rellena a un múltiplo de 8 bytes. Para tu 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;
Puedes optimizar tu estructura así:
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)
Hay algunos bytes no utilizados entre algunos miembros para mantener las alineaciones correctas . Por ejemplo, un puntero por defecto reside en límites de 4 bytes por eficiencia, es decir, su dirección debe ser un múltiplo de 4. Si la estructura contiene solo un carácter y un puntero
struct {
char a;
void* b;
};
entonces b
no puede usar los adders # 1, debe colocarse en el # 4.
0 1 2 3 4 5 6 7
+---+- - - - - -+---------------+
| a | (unused) | b |
+---+- - - - - -+---------------+
En su caso, los 7 bytes adicionales provienen de 3 bytes debido a la alineación de int*
, y 4 bytes debido a la alineación de 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 |
+-------------------------------+
Para ampliar un poco la excelente respuesta de KennyDM (Kenny: robe esto para complementar su respuesta si así lo desea), es probable que su estructura de memoria se vea como una vez que el compilador haya 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 |
+------------------------------------+
Por lo tanto, debido a la brecha de 3 bytes entre "ch" y "p", y la brecha de 4 bytes entre "p" y "d", obtiene un relleno de 7 bytes para su estructura, por lo tanto, el tamaño de 24 bytes. Como el double
su entorno tiene una alineación de 8 bytes (es decir, debe residir en su propio bloque de 8 bytes, como puede ver arriba), la struct
completa también estará alineada con 8 bytes sobre todo, e incluso se podrá reordenar. Las variables no alterarán el tamaño de 24 bytes.
También a veces necesita la estructura para mantener el orden que necesita. En estos casos, si está utilizando gcc, debe usar la __attribute__((packed))
.
Vea también esto para más información.
Ver la lista de preguntas frecuentes comp.lang.c · Pregunta 2.12 :
¿Por qué mi compilador está dejando agujeros en las estructuras, desperdiciando espacio e impidiendo la E / S "binaria" a archivos de datos externos? ¿Puedo desactivar esto o controlar la alineación de los campos de la estructura?