c++ - reales - libro de android studio en español pdf
¿Por qué está aquí el tamaño de la estructura 5 empaquetada en lugar de 4 bytes? (4)
El problema es que __attribute__((packed))
no realiza el empaquetado bit a bit. Simplemente garantiza que no hay relleno entre los miembros de la struct
. Puede probar este ejemplo más simple, donde el tamaño también se informa como 5:
typedef struct structTag {
struct {
uint32_t messageID : 26;
uint8_t priority : 3;
} __attribute__ ((packed));
uint8_t canFlags : 3;
} __attribute__ ((packed)) idSpecial;
El embalaje de bit a bit solo es posible para los miembros del campo de bit. Deberá rediseñar su estructura para que sea una unión de una estructura con bitfields messageID / priority / canFlags, y una estructura con bitfields rowID / canFlags. En otras palabras, necesitará tener alguna duplicación o recurrir a accesor o macros o funciones miembro.
Ver ejemplo en línea: ejemplo de Ideone
struct {
union {
struct {
uint32_t messageID : 26;
uint8_t priority : 3;
} __attribute__ ((packed));
uint32_t rawID : 29;
} __attribute__ ((packed));
uint8_t canFlags : 3;
} __attribute__ ((packed)) idSpecial;
¿Por qué el compilador informaría el tamaño de la estructura como 5 bytes en lugar de 4 aquí? Debe contener 32 bits.
En algunos compiladores, para "fusionar" los bits, todos los elementos deben ser del mismo tipo. Así que uint32_t
donde ahora tiene uint8_t
; parece que este no es el caso en el compilador que IdeOne usa aunque
[No importa qué, todavía depende del compilador cómo fusiona los bits, por lo que la única forma de garantizar por uint32_t
que sus datos se almacenen como 32 bits es usar un único uint32_t
y declarar una clase que uint32_t
los cambios pertinentes y anding / oring para manipular el valor: la única garantía que tiene es que UN elemento en su estructura tendrá al menos tantos bits como haya solicitado]
Como han señalado otros, no puede iniciar una estructura nueva que no sea un límite de bytes. Lo arreglé teniendo una segunda estructura dentro de la unión, así: http://ideone.com/Mr1gjD
#include <stdint.h>
#include <stdio.h>
typedef struct structTag {
union {
struct {
uint32_t messageID : 26; /* 26bit message id, 67108864 ids */
uint8_t priority : 3; /* priority: MUST BE 0 */
} __attribute__ ((packed));
struct {
uint32_t rawID : 29;
uint8_t canFlags : 3;
};
} __attribute__ ((packed));
} __attribute__ ((packed)) idSpecial;
int main() {
printf("size: %d", sizeof(idSpecial));
return 0;
}
Los datos se organizan y acceden a la memoria de la computadora utilizando la alineación de la estructura de datos. Que tiene dos problemas relacionados
- Alineación
- Relleno
Cuando la computadora realiza una operación de escritura, generalmente se escribe en múltiples de 4 bytes (para sistemas de 32 bits). Una razón para este acto es el objetivo de aumentar el rendimiento. Entonces, cuando está escribiendo cualquier estructura de datos, que tiene la primera variable de 1 byte y luego datos de variables de 4 bytes, hará un relleno después de los primeros datos de 1 byte para alinearlo en los límites de 32 bits.
struct {
union {
struct {
uint32_t messageID : 26;
uint8_t priority : 3;
} __attribute__ ((packed));
uint32_t rawID : 29;
} __attribute__ ((packed));
uint8_t canFlags : 3;
} __attribute__ ((packed)) idSpecial;
Ahora, en la estructura de datos anterior, está utilizando __attribute__ ((packed))
que significa que no hay relleno. Entonces uint32_t es de 4 bytes, pero está seguro de que tiene 26 bits y 3 bits para prioridad. Ahora, como tiene ambas variables en una estructura, reservará 32 bits en lugar de 29 para que la información de su primera estructura esté alineada en los límites.
Ahora para canFlags Necesitará otros bytes. Entonces eso hace 5 bytes en lugar de 4.
Se debe a la alineación de memoria: el compilador no inicia canFlags
en el medio de un byte, sino que lo iniciará al principio del siguiente byte (probablemente *). Entonces tiene cuatro bytes para su unión inicial y un byte para canFlags
.
Si, por ejemplo, movió canFlags
a la unión, tendría (probablemente *) tamaño 4:
typedef struct structTag {
union {
struct {
uint32_t messageID : 26; /* 26bit message id, 67108864 ids */
uint8_t priority : 3; /* priority: MUST BE 0 */
} __attribute__ ((packed));
uint32_t rawID : 29;
uint8_t canFlags : 3; /* <==== Moved */
} __attribute__ ((packed));
} __attribute__ ((packed)) idSpecial;
Ejemplo actualizado sobre ideone . Obviamente, ese cambio específico probablemente no es lo que quieres; Solo estoy demostrando que el problema es comenzar un nuevo campo no en un límite de bytes.
* "probablemente" porque finalmente depende del compilador.