Comprensión de las variaciones del tamaño de las estructuras en C/C++: el impacto del ordenamiento de los miembros y la alineación de los datos

Resuelto Rakshith B S asked hace 10 meses • 0 respuestas

¿Por qué el tamaño de struct bit_man1 genera 8 bytes mientras que struct bit_man2 genera 4 bytes, aunque ambas estructuras contienen los mismos tipos y cantidad de datos? Considere las estructuras definidas a continuación:


#include <stdio.h>
// packing is done in 4 bytes size since int is the biggest in struct
struct bit_man1 {
    int a:5;        //5 bits                                 
    int b:8;        //5+8 =13 bits
    char abc[2];    //2 bytes 8 +8 +13= 29  bit
    int z:2;       // 2 bits 29+2 =31
  
        
};

struct bit_man2 {
    int a:5;        //5 bits                                 
    int b:8;        //5+8 =13 bits
    int z:2;        // 2 bits 13+2=15
    char abc[2];    //2 bytes 8 +8 +15= 31  bit
  
        
};

int main() {
 
   
    printf("Size of bit_man1: %zu bytes\n", sizeof(struct bit_man1));
    printf("Size of bit_man2: %zu bytes\n", sizeof(struct bit_man2));
    return 0;
}

versión gcc

$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/11/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none:amdgcn-amdhsa
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 11.4.0-1ubuntu1~22.04' --with-bugurl=file:///usr/share/doc/gcc-11/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++,m2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-11 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --enable-libphobos-checking=release --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --enable-cet --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-11-XeT9lY/gcc-11-11.4.0/debian/tmp-nvptx/usr,amdgcn-amdhsa=/build/gcc-11-XeT9lY/gcc-11-11.4.0/debian/tmp-gcn/usr --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu --with-build-config=bootstrap-lto-lean --enable-link-serialization=2
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 11.4.0 (Ubuntu 11.4.0-1ubuntu1~22.04)

Pero obtenemos una salida como esa.

Size of bit_man1: 8 bytes
Size of bit_man2: 4 bytes

Como el empaquetado prioriza 4 bytes, ¿no debería empaquetarse el int z:2 (2 bits) en los 29 bits, lo que da como resultado 31 bits? ¿Hay alguna razón por la cual el compilador asigna otros 4 bytes?

Rakshith B S avatar Feb 17 '24 00:02 Rakshith B S
Aceptado

Los campos de bits adyacentes se pueden agrupar en la misma unidad de asignación, pero los campos de bits y los que no lo son, no. Esto significa que el abcmiembro ocupará 2 bytes completos y no ocupará ningún byte parcial, como un bit no utilizado en una unidad que contiene un campo de bits.

En el primer caso, se comienza con dos campos de bits que suman un total de 13 bits. Estos encajan en una única unidad de asignación de 2 bytes. La charmatriz ocupa los siguientes 2 bytes completos. Luego, el campo de bits restante ocupa otro byte. Luego, dado que el tipo base de los campos de bits es intla estructura, se completan otros 3 bytes (suponiendo que intocupa 4 bytes) para un total de 8.

En el segundo caso se empieza con tres campos de bits que suman un total de 15 bits. Estos encajan en una única unidad de asignación de 2 bytes como en el caso anterior. La charmatriz ocupa los siguientes 2 bytes completos para un total de 4 bytes utilizados.

dbush avatar Feb 16 '2024 17:02 dbush