Выравнивание данных структуры с помощью malloc - PullRequest
0 голосов
/ 03 сентября 2018

Считайте, что у меня есть структура как показано ниже.

struct st
{
  char c;
  double d;
  int i;
};

В соответствии с размером выравнивания памяти struct st будет (1 + 7 (дополненный) + 8 + 4 + 4 (дополненный)) = 24 байта

Когда я делаю malloc, как показано ниже

struct st *p = malloc(sizeof(*p));

будет таким же, как

struct st *p = malloc(13);

Как malloc выделяет 24 байта для выравнивания памяти, поскольку мы просто передаем размер структуры (13 байтов)?

Ответы [ 2 ]

0 голосов
/ 03 сентября 2018

Вопрос ошибочно предполагает, что

struct st *p = malloc(sizeof(*p));

совпадает с

struct st *p = malloc(13);

Это не так. Для проверки

printf ("Size of st is %d\n", sizeof (*p));

который печатает 24, а не 13.

Правильный способ распределения и управления структурами - с помощью sizeof(X), а не путем предположения о том, как элементы упакованы или выровнены.

0 голосов
/ 03 сентября 2018

Как malloc выделяет 24 байта для выравнивания памяти, поскольку мы просто передаем размер структуры (13 байтов)?

Это не так. Если malloc(13) возвращает хотя бы 24 байта, это странная реализация malloc. malloc разрешено выделять больше места, чем необходимо, и часто необходимо для выравнивания байтов и различных других причин реализации.

Мы можем увидеть это с помощью простой программы.

struct st *a = malloc(13);
struct st *b = malloc(13);
struct st *c = malloc(13);
struct st *d = malloc(13);

printf("%p\n%p\n%p\n%p\n", a, b, c, d);

0x602000003210
0x602000003230
0x602000003250
0x602000003270

Как видно из адресов, указатели, возвращаемые malloc(13), имеют между собой 32 байта. Много, чтобы соответствовать вашим 24 байтов, и программа "работает". Даже malloc(1) возвращает тот же результат.

Но если мы сделаем вашу структуру немного больше ...

struct st {
  char c;
  double b;
  double a;
  double d;
  int i;
};

Это 40 байтов, выровненных. Теперь он не помещается в 32 байта, и мы видим искажение, потому что память структуры перекрывается друг с другом.

#include <stdlib.h>
#include <stdio.h>

struct st {
  char c;
  double b;
  double a;
  double d;
  int i;
};

void print_struct(struct st* st) {
    printf("%c %lf %d\n", st->c, st->d, st->i);
}

int main() {
    const size_t struct_size = sizeof(char) + (sizeof(double) * 3) + sizeof(int);

    printf("sizeof(struct st): %zu\n", sizeof(struct st));
    printf("sizeof fields added together: %zu\n", struct_size);

    struct st *a = malloc(13);
    struct st *b = malloc(13);
    struct st *c = malloc(13);
    struct st *d = malloc(13);

    printf("%p\n%p\n%p\n%p\n", a, b, c, d);

    a->c = 'a';
    a->d = 1.0;
    a->i = 1;

    b->c = 'b';
    b->d = 2.0;
    b->i = 2;

    c->c = 'c';
    c->d = 3.0;
    c->i = 3;

    d->c = 'd';
    d->d = 4.0;
    d->i = 4;

    print_struct(a);
    print_struct(b);
    print_struct(c);
    print_struct(d);
}

sizeof(struct st): 40
sizeof fields added together: 29
0x602000003210
0x602000003230
0x602000003250
0x602000003270
a 1.000000 98
b 2.000000 99
c 3.000000 100
d 4.000000 4

98 является b. 99% 1027 *. 100% d. Это означает, что a->i перекрывается с b->c, b->i перекрывается с c->c и т. Д.

...