как получить адрес поля структуры?

351
12 апреля 2017, 15:37

Написал программу на вывод чисел в байтах и адреса хранения этих байтов,но преподаватель говорит,что адреса полей хранятся в сложных типах данных хранятся не последовательно,а мой вариант программы не верен. Собственно вопрос,как получить адрес поля структуры ? Код приложил:

#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <locale.h>
using namespace std;
typedef unsigned char *byte_ptr;
void print_int(byte_ptr start, int size)
{
    cout << "Вывод числа типа int ";
    for (int i = 0; i < size; i++)
        printf("\n|%p|%2x|", &start[i], start[i]);
}
void print_float(byte_ptr start, int size)
{
    cout << "Вывод числа типа float ";
    for (int i = 0; i < size; i++)
        printf("\n|%p|%2x|", &start[i], start[i]);
}
void print_double(byte_ptr start, int size)
{
    cout << "Вывод числа типа double ";
    for (int i = 0; i < size; i++)
        printf("\n|%p|%2x|", &start[i], start[i]);
}
int main()
{
    setlocale(0, "");
    struct Numbers
    {
        int x;
        float y;
        double z;
    } Byte;
    Byte.x = 15;
    Byte.y = 15;
    Byte.z = 15;
    print_int((byte_ptr) &Byte.x, sizeof(Byte.x));
    cout << endl;
    print_float((byte_ptr) &Byte.y, sizeof(Byte.y));
    cout << endl;
    print_double((byte_ptr) &Byte.z, sizeof(Byte.z));
    cout << endl;
    system("PAUSE");
    return 0;
}

Как это выглядит на консоли

Answer 1

как получить адрес поля структуры?

Так вы же правильно это делаете:

(byte_ptr)&Byte.x

Правда, приведение указателей к другому типу - не очень хорошая идея, но это уже другой вопрос.

Далее, в функциях print_... вы пытаетесь разбить это число на байты и вывести их по порядку с адресом, но почему-то в первом случае забыли оператор взятия адреса:

printf("\n|%p|%2x|", &start[i], start[i]);

Данные хранятся в структурах последовательно, но между ними могут появляться пустые пространства. Например, если у вас 32-разрядная архитектура, и первое поле структуры имеет тип char, а второе - float, то между ними появятся 3 пустых байта. Это называется выравниванием.

И, да, AnT верно заметил, что ваши три функции абсолютно одинаковы. Если вы в функцию, печатающую float, передадите адрес на double, то она правильно его напечатает.

UPD. Чтобы увидеть пустые пространства между полями структуры, нужно расположить эти поля так, чтобы это пространство потребовалось. Вот здесь хорошо описано, когда и почему эти пространства появляются, и как их избежать.

В вашем случае, скорее всего, можно просто double поставить посередине. Или добавить char в начало.

Answer 2

Если использовать возможности препроцессора, то можно описать все поля в одном массиве структур и подробно все напечатать (вместе с промежутками между полями).

#include <stdio.h>
int main() {
  struct {
    int x;
    double z;
    float y;
  } bytes = {1, 1, 0};
  struct {
    void *addr;
    size_t len;
    const char *type, *name;
  } info[] = {
#define FIELD(f,T) {&(f), sizeof(f), #T, #f}
    FIELD(bytes.x, int), FIELD(bytes.z, double), FIELD(bytes.y, float),
#undef FIELD    
    {&bytes + 1, 0}};
  unsigned char *b = (unsigned char *)&bytes,
    *eb = (unsigned char *)(&bytes + 1);
  printf("struct bytes (%p:%p %zu bytes) content:\n",
         b, eb, sizeof(bytes));
  for (size_t i = 0; info[i].len; i++) {
    printf("%p:%p %2zu %s %s\t: " ,
           info[i].addr, (char *)info[i].addr + info[i].len,
           info[i].len, info[i].type, info[i].name);
    for (eb = b + info[i].len; b < eb; b++)
      printf("%02x ", *b);
    for (; (void *)b != info[i + 1].addr; b++)
      printf(".. ");
    puts("");
  }
}

Получится что-то вроде такого (в 64-бит Linux)

avp@avp-ubu1:hashcode$ g++ tt.cpp -Wall -O3 -std=c++17
avp@avp-ubu1:hashcode$ ./a.out
struct bytes (0x7ffc4bf91040:0x7ffc4bf91058 24 bytes) content:
0x7ffc4bf91040:0x7ffc4bf91044  4 int bytes.x    : 01 00 00 00 .. .. .. .. 
0x7ffc4bf91048:0x7ffc4bf91050  8 double bytes.z : 00 00 00 00 00 00 f0 3f 
0x7ffc4bf91050:0x7ffc4bf91054  4 float bytes.y  : 00 00 00 00 .. .. .. .. 
avp@avp-ubu1:hashcode$ 

Последний элемент массива описателей полей структуры надо инициализировать адресом, следующим за структурой и нулевой длиной.

READ ALSO
Парсер данных в кольцевом буфере

Парсер данных в кольцевом буфере

Программирую STM32 на C\C++, имеется кольцевой буфер входящих данных (не важно, текстовых или бинарных)Естественно известен формат данных, которые...

207