Выравнивание данных для структуры C - PullRequest
3 голосов
/ 03 июля 2019

В CS: APP существует проблема (3.45) о смещении байтов всех полей в следующей структуре.

struct {
  int    *a;
  float  b;
  char   c;
  short  d;
  long   e;
  double f;
  int    g;
  char   *h;
} rec;

Вот ответ из книги, который дает c заполнение тремя байтами, d заполнение двумя байтами и g заполнение четырьмя байтами.

field  size  offset
-----  ----  ------
a      8     0
b      4     8
c      1     12
d      2     16
e      8     24
f      8     32
g      4     40
h      8     48

А вот мое решение, которое дает c однобайтовое заполнение и g четырехбайтовое заполнение.

field  size  offset
-----  ----  ------
a      8     0
b      4     8
c      1     12
d      2     14
e      8     16
f      8     24
g      4     32
h      8     40

Итак, в чем проблема с моим решением? Кажется, это соответствует правилу выравнивания (отредактируйте * «правило», это просто упрощенное обобщение концепции, оно не закончено или не общее), смещение всего объекта кратно размеру объекта.

Был бы очень благодарен за любое объяснение.

Ответы [ 2 ]

3 голосов
/ 04 июля 2019

Ответ зависит от параметров компилятора, платформы и компиляции.Некоторые примеры: enter image description here

https://godbolt.org/z/4tAzB_

Автор книги не понимает тему, которую я боюсь.

3 голосов
/ 03 июля 2019

Учитывая размеры показанных объектов и правила выравнивания, которые говорят, что каждый из этих объектов должен быть выровнен по кратному его размеру, тогда, когда структура выложена только с отступом, необходимым для выравнивания, смещения должны быть такими, как показанов решении Тетрау.Книжное решение неверно.

Смещения, показанные в решении Tetrau, на самом деле являются смещениями, созданными Apple LLVM 10.0.1 с компиляцией Clang 1001.0.46.4 для x86-64;выходные данные из программы ниже:

0
8
12
14
16
24
32
40
48
struct foo {
  int    *a;
  float  b;
  char   c;
  short  d;
  long   e;
  double f;
  int    g;
  char   *h;
} rec;


#include <stddef.h>
#include <stdio.h>


int main(void)
{
    printf("%zu\n", offsetof(struct foo, a));
    printf("%zu\n", offsetof(struct foo, b));
    printf("%zu\n", offsetof(struct foo, c));
    printf("%zu\n", offsetof(struct foo, d));
    printf("%zu\n", offsetof(struct foo, e));
    printf("%zu\n", offsetof(struct foo, f));
    printf("%zu\n", offsetof(struct foo, g));
    printf("%zu\n", offsetof(struct foo, h));
    printf("%zu\n", sizeof rec);
}

Примечание

Правило, что объект требует выравнивания, кратного его размеру, подходит для этого упражнения, но оно должно бытьотметил, что это не общее правило.Машина может иметь некоторый восьмибайтовый объект, но иметь только шину и другие характеристики доступа к памяти, которые имеют ширину четыре байта, поэтому она будет заботиться только о четырехбайтовом выравнивании максимум для любого объекта.Или элемент структуры может быть другой структурой, скажем, размером девять байтов (например, struct bar { char x[9]; }), но его требование выравнивания не будет девятью байтами.

...