Доступ к членам структуры с использованием базового адреса - PullRequest
0 голосов
/ 03 октября 2018

Не могли бы вы помочь объяснить, почему следующая программа правильно печатает значения всех элементов структуры?

struct st
{
  int i;
  char c1;
  int j;
  char c2;
};

int main()
{
  struct st a = {5, 'i', 11, 'H'};
  struct st * pa = &a;

  int first;
  char second;
  int third;
  char fourth;

  first = *((int*)pa);
  second = *((char*)pa + 4); /* offset = 4 bytes = sizeof(int) */
  third = *((int*)pa + 2); /* why (pa + 2) here? */
  fourth = *((char*)pa + 12); /* why (pa + 12) here? */
  printf ("first = %d, second = %c, third = %d, fourth = %c\n", first, second, third, fourth);
  return 0;
}

Вывод: первый = 5, второй = i, третий = 11, четвертый = H

Как я могу сделать вышеуказанную программу обобщенной?

Ответы [ 5 ]

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

Как сделать вышеупомянутую программу обобщенной?

Единственный способ обеспечить ее надежную работу - не угадывать смещение.Используйте стандартный макрос offsetof и всегда выполняйте арифметику указателя с помощью символьного указателя:

first = *(int*)((char*)pa + offsetof(struct st, i));

Вам не нужно называть поле в точке, к которой вы обращаетесь, новам определенно следует использовать макрос для вычисления результата, если вы собираетесь передать его в свою функцию.

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

Как и в других ответах - padding.

Но некоторые компиляторы позволяют упаковывать ваши структуры, удаляя (в большинстве случаев) отступы.

gcc:

struct __attribute__((packed)) st
{
....
}

Код, который обращается к упакованным структурам, может быть менее эффективным и длинным.

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

Это из-за заполнения structure.

После заполнения ваш structure будет выглядеть следующим образом.

struct st
{
  int i;
  char c1;
  char padding[3]; // for alignment of j.
  int j;
  char c2; 
  char padding[3]; // for alignment of structure.
};

Следовательно

first = *((int*)pa);
  second = *((char*)pa + 4); /* offset = 4 bytes = sizeof(int) */
  third = *((int*)pa + 2); /* offset = 8 bytes(pointer arithmetic) to point to int j*/
  fourth = *((char*)pa + 12); /* offset = 12 bytes to point to char c2*/

Для получения дополнительной информации о заполнении структуры читайте Data_structure_alignment

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

При создании структуры все переменные занимают одинаковое количество места (32 бита), оставшиеся неиспользуемые биты заполняются.Так что даже если вы определите char в структуре, это займет 4 байта.Это связано с тем, что ваш процессор обрабатывает данные в 32-битном формате, даже если впоследствии используется меньше битов.Память на другой стороне хранит 1 байт для каждого адреса, но когда данные выбираются ЦП, данные будут адаптированы к архитектуре шины (которая зависит от процессора).

Также обратите внимание, что смещение зависитна указателе, который вы используете.char* в этом случае увеличится на 1, а int* на 4.

Это также означает, что код не является переносимым, поскольку, например, int не может быть определено дляодного размера на разных архитектурах.

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

Это из-за байтов заполнения, добавленных в структуру.Три добавленных байта будут добавлены после char second;, потому что за char следует int (элемент с большим выравниванием), поэтому байты заполнения будут вставлены, чтобы выравнивание было кратным выравниванию большего элемента.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...