Данный подсказка участнику в структуре, запишите стандартную программу, которая возвращает указатель на структуру

Вот вопрос об интервью, который я видел на некотором форуме. Я пытался выяснить, как это работает, но я не вполне получаю его. Кто-то мог объяснить, как это работает?

Q: Данный подсказка участнику в структуре, запишите стандартную программу, которая возвращает указатель на структуру.

struct s 
{
   ...
   int a;
   …
};

struct s *get_s_ptr(int *a_ptr)
{
   // implement this.
}

Ответ:

struct s* get_s_ptr(int *a_ptr)
{
   return (struct s*)((char*)a_ptr - (int)&((struct s*)0)->a);
}
9
задан Steve 20 June 2010 в 02:30
поделиться

4 ответа

Как это работает?

Основное уравнение здесь (вся арифметика в байтах):

address of struct member s->a == s + byte offset of a

Учитывая тип s , один компилятор и На одной целевой машине они определили байтовое смещение a - то же самое для каждой структуры типа s.

Вам дана левая часть, и ваш собеседник попросил вас восстановить s . Вы можете сделать это, получив новое уравнение; вычтите байтовое смещение с обеих сторон:

address of struct member s->a - byte offset of a == s

В задаче вам дан адрес s-> a , но вы должны вычислить байтовое смещение. Для этого вы снова используете исходное уравнение с s , установленным в ноль:

address of struct member s->a where s is zero == zero + byte offset of a 
                                              == byte offset of a

Левая часть в C строится следующим образом

struct pointer s where s is zero                            (struct s *)0
struct member s->a where s is zero                          ((struct s*)0)->a
address of s->a where s is zero                             &((struct s*)0)->a

Заключительные шаги:

  1. Чтобы сделать арифметику допустимой для C, это смещение байта приводится к целому числу.
  2. Чтобы убедиться, что вычитание выполняется в байтах, a_ptr приводится к char * .
  3. Для придания результату правильного типа разница приводится к struct s * .

Приложение: Как указывает Эли Бендерски, вам следует избегать ситуаций, в которых этот код был бы необходим. Почти всегда есть лучший способ.

12
ответ дан 4 December 2019 в 09:12
поделиться

Вы можете использовать макрос offsetof.

struct s* get_s_ptr(int *a_ptr)
{
   return (struct s*)((char*)a_ptr - offsetof(struct s,a) );
}

Я опаздываю. мое интернет соединение медленное.

4
ответ дан 4 December 2019 в 09:12
поделиться

Ответ: не работает. Это не работает, даже если на первый взгляд может показаться, что "работает". В "ответе" делается попытка разыменовать нулевой указатель, что приводит к неопределенному поведению. Поэтому, если ваше представление о "работе" не включает неопределенное поведение, этот ответ не работает.

В этом решении есть и другие проблемы, кроме попытки разыменовать нулевой указатель (хотя одного этого вполне достаточно, чтобы выбросить этот "ответ" в мусорную корзину). Еще одна проблема заключается в том, что результатом (struct s*) 0 является нулевой указатель типа struct s *. Язык не дает никаких гарантий относительно фактического физического значения нулевого указателя. Он легко может оказаться чем-то вроде 0xBAADFOOD, что сразу испортит предполагаемую функциональность "ответа".

Правильная реализация подразумеваемой техники предполагает использование стандартного макроса offsetof (уже предложенного в ответе Nyan, но я повторю его еще раз)

struct s* get_s_ptr(int *a_ptr)
{
   return (struct s*) ((char *) a_ptr - offsetof(struct s, a));
}
6
ответ дан 4 December 2019 в 09:12
поделиться

Думал, что это будет полезно,

/* offsetof example */
#include <stdio.h>
#include <stddef.h>

struct mystruct {
    char singlechar;
    char arraymember[10];
    char anotherchar;
};

int main ()
{
    printf ("offsetof(mystruct,singlechar) is %d\n",offsetof(mystruct,singlechar));
    printf ("offsetof(mystruct,arraymember) is %d\n",offsetof(mystruct,arraymember));
    printf ("offsetof(mystruct,anotherchar) is %d\n",offsetof(mystruct,anotherchar));

    return 0;
}

Вывод:

offsetof(mystruct,singlechar) is 0
offsetof(mystruct,arraymember) is 1
offsetof(mystruct,anotherchar) is 11

Итак, в вашем случае

return (struct s*) ((char *) a_ptr - offsetof(struct s, a));
  • приведите aptr к char *
  • , вычтите смещение a относительно struct s
  • , приведенная к struct s *
  • , возвращает результирующий ptr
1
ответ дан 4 December 2019 в 09:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: