in

c – Estructura acolchada y empaquetada

apple touch icon@2

(Las respuestas anteriores explicaron la razón con bastante claridad, pero no parece totalmente claro sobre el tamaño del relleno, por lo que agregaré una respuesta de acuerdo con lo que aprendí de El arte perdido del empaque de estructuras, ha evolucionado para no limitarse a C, pero también aplicable a Go, Rust.)


Alineación de memoria (para estructura)

Normas:

  • Antes de cada miembro individual, habrá un relleno para que comience en una dirección que sea divisible por su tamaño.
    por ejemplo, en un sistema de 64 bits,int debe comenzar en la dirección divisible por 4, y long por 8, short por 2.
  • char y char[] son especiales, podrían ser cualquier dirección de memoria, por lo que no necesitan relleno antes que ellos.
  • Para struct, aparte de la necesidad de alineación para cada miembro individual, el tamaño de la estructura completa en sí se alineará a un tamaño divisible por el tamaño del miembro individual más grande, mediante el relleno al final.
    por ejemplo, si el miembro más grande de la estructura es long luego divisible por 8, int luego a las 4, short luego por 2.

Orden de miembro:

  • El orden de los miembros puede afectar el tamaño real de la estructura, así que téngalo en cuenta. por ejemplo, el stu_c y stu_d del ejemplo siguiente tienen los mismos miembros, pero en diferente orden, y dan como resultado un tamaño diferente para las 2 estructuras.

Dirección en memoria (para estructura)

Normas:

  • Sistema de 64 bits
    La dirección de estructura comienza desde (n * 16) bytes. (Puede ver en el siguiente ejemplo, todas las direcciones hexadecimales impresas de estructuras terminan con 0.)
    Razón: el miembro de estructura individual más grande posible es de 16 bytes (long double).
  • (Actualizar) Si una estructura solo contiene un char como miembro, su dirección puede comenzar en cualquier dirección.

Espacio vacio:

  • El espacio vacío entre 2 estructuras podría ser utilizado por variables que no son de estructura que podrían encajar.
    por ejemplo, en test_struct_address() debajo, la variable x reside entre estructuras adyacentes g y h.
    Sin importar si x se declara, hla dirección no cambiará, x acaba de reutilizar el espacio vacío que g desperdiciado.
    Caso similar para y.

Ejemplo

(para sistema de 64 bits)

memory_align.c:

/**
 * Memory align & padding - for struct.
 * compile: gcc memory_align.c
 * execute: ./a.out
 */ 
#include <stdio.h>

// size is 8, 4 + 1, then round to multiple of 4 (int's size),
struct stu_a {
    int i;
    char c;
};

// size is 16, 8 + 1, then round to multiple of 8 (long's size),
struct stu_b {
    long l;
    char c;
};

// size is 24, l need padding by 4 before it, then round to multiple of 8 (long's size),
struct stu_c {
    int i;
    long l;
    char c;
};

// size is 16, 8 + 4 + 1, then round to multiple of 8 (long's size),
struct stu_d {
    long l;
    int i;
    char c;
};

// size is 16, 8 + 4 + 1, then round to multiple of 8 (double's size),
struct stu_e {
    double d;
    int i;
    char c;
};

// size is 24, d need align to 8, then round to multiple of 8 (double's size),
struct stu_f {
    int i;
    double d;
    char c;
};

// size is 4,
struct stu_g {
    int i;
};

// size is 8,
struct stu_h {
    long l;
};

// test - padding within a single struct,
int test_struct_padding() {
    printf("%s: %ldn", "stu_a", sizeof(struct stu_a));
    printf("%s: %ldn", "stu_b", sizeof(struct stu_b));
    printf("%s: %ldn", "stu_c", sizeof(struct stu_c));
    printf("%s: %ldn", "stu_d", sizeof(struct stu_d));
    printf("%s: %ldn", "stu_e", sizeof(struct stu_e));
    printf("%s: %ldn", "stu_f", sizeof(struct stu_f));

    printf("%s: %ldn", "stu_g", sizeof(struct stu_g));
    printf("%s: %ldn", "stu_h", sizeof(struct stu_h));

    return 0;
}

// test - address of struct,
int test_struct_address() {
    printf("%s: %ldn", "stu_g", sizeof(struct stu_g));
    printf("%s: %ldn", "stu_h", sizeof(struct stu_h));
    printf("%s: %ldn", "stu_f", sizeof(struct stu_f));

    struct stu_g g;
    struct stu_h h;
    struct stu_f f1;
    struct stu_f f2;
    int x = 1;
    long y = 1;

    printf("address of %s: %pn", "g", &g);
    printf("address of %s: %pn", "h", &h);
    printf("address of %s: %pn", "f1", &f1);
    printf("address of %s: %pn", "f2", &f2);
    printf("address of %s: %pn", "x", &x);
    printf("address of %s: %pn", "y", &y);

    // g is only 4 bytes itself, but distance to next struct is 16 bytes(on 64 bit system) or 8 bytes(on 32 bit system),
    printf("space between %s and %s: %ldn", "g", "h", (long)(&h) - (long)(&g));

    // h is only 8 bytes itself, but distance to next struct is 16 bytes(on 64 bit system) or 8 bytes(on 32 bit system),
    printf("space between %s and %s: %ldn", "h", "f1", (long)(&f1) - (long)(&h));

    // f1 is only 24 bytes itself, but distance to next struct is 32 bytes(on 64 bit system) or 24 bytes(on 32 bit system),
    printf("space between %s and %s: %ldn", "f1", "f2", (long)(&f2) - (long)(&f1));

    // x is not a struct, and it reuse those empty space between struts, which exists due to padding, e.g between g & h,
    printf("space between %s and %s: %ldn", "x", "f2", (long)(&x) - (long)(&f2));
    printf("space between %s and %s: %ldn", "g", "x", (long)(&x) - (long)(&g));

    // y is not a struct, and it reuse those empty space between struts, which exists due to padding, e.g between h & f1,
    printf("space between %s and %s: %ldn", "x", "y", (long)(&y) - (long)(&x));
    printf("space between %s and %s: %ldn", "h", "y", (long)(&y) - (long)(&h));

    return 0;
}

int main(int argc, char * argv[]) {
    test_struct_padding();
    // test_struct_address();

    return 0;
}

Resultado de ejecución – test_struct_padding():

stu_a: 8
stu_b: 16
stu_c: 24
stu_d: 16
stu_e: 16
stu_f: 24
stu_g: 4
stu_h: 8

Resultado de ejecución – test_struct_address():

stu_g: 4
stu_h: 8
stu_f: 24
address of g: 0x7fffd63a95d0  // struct variable - address dividable by 16,
address of h: 0x7fffd63a95e0  // struct variable - address dividable by 16,
address of f1: 0x7fffd63a95f0 // struct variable - address dividable by 16,
address of f2: 0x7fffd63a9610 // struct variable - address dividable by 16,
address of x: 0x7fffd63a95dc  // non-struct variable - resides within the empty space between struct variable g & h.
address of y: 0x7fffd63a95e8  // non-struct variable - resides within the empty space between struct variable h & f1.
space between g and h: 16
space between h and f1: 16
space between f1 and f2: 32
space between x and f2: -52
space between g and x: 12
space between x and y: 12
space between h and y: 8

Por lo tanto, la dirección de inicio para cada variable es g: d0 x: dc h: e0 y: e8

ingrese la descripción de la imagen aquí

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Método Python String lower ()

E5xX9nWjMJ7TdjqEtUamT9 1200 80

Pokemon Air es básicamente un saltador espacial de Pikachu y estamos aquí para ello