2016-04-11 10 views
1

Я искал очень долго и упорно (ссылки в самом конце) для объяснения реализации offsetof MACRO:Сложность в понимании offsetof MACRO

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) 

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

Вот некоторые ссылки я попытался понимание:

  1. http://www.viva64.com/en/b/0301/
  2. http://www.embedded.com/design/prototyping-and-development/4024941/Learn-a-new-trick-with-the-offsetof--macro
  3. http://www.geeksforgeeks.org/the-offsetof-macro/
  4. How does the C offsetof macro work?
  5. Does dereference a NULL pointer guarantee to crash a program in C/C++?

То, что я ищу и пытаюсь понять, - шаг за шагом, смущая понимание того, как компилятор интерпретирует определение MACRO, которое в конечном итоге объяснит, как NULL-указатель фактически не разыменовывается.

EDIT: Несмотря на то, что другие вопросы ответили на мой вопрос, они имеют смысл для меня, как указано в исходном сообщении. Ответ @dasblinkenlight проливает свет на точную проблему, с которой я столкнулся с другими вопросами, и как это получается, что мы фактически не разыскиваем указатель.

+1

Что еще вам нужно, чем этот ответ? http://stackoverflow.com/a/7898055/4966481 –

+1

Возможный дубликат [Как работает макрос смещения C?] (http://stackoverflow.com/questions/7897877/how-does-the-c-offsetof- macro-work) –

+1

Если 'a' является указателем на адрес 1234, а' b' является членом 'a' при смещении 12, то что такое' & a-> b'? Теперь, если 'a' указывает на адрес 0, что такое' & a-> b'? Как вы это делали в своей голове без разыгрывания 'a'? – immibis

ответ

3

В частности, разыменование NULL для получения смещения элемента в структуре.

Там нет разыменования указателя происходит, потому что эффект от оператора -> отменяются оператором &:

  • Это будет разыменование NULL: ((TYPE *)0)->MEMBER
  • Добавление & перед его вычислением адреса: &((TYPE *)0)->MEMBER

Многие статьи затушевывают причину, говоря, что указатель NULL на самом деле никогда не разыменован, но для меня это не имеет смысла.

Рассмотрим этот пример в качестве иллюстрации:

int a; 
int *p = &a; 
int b = *p;  // <<== This is a dereference 
int *q = &(*p); // <<== This is not a dereference 

Два оператора, * и &, отменить действие друг друга. Оператор -> является «синтаксическим сахаром» поверх * и ., поэтому & также может отменить его эффекты.

Когда компилятор видит выражение somePointer->a он принимает числовое значение указателя somePointer, добавляет смещение элемента a, и узнает место в памяти, на которой вы можете работать. Есть три вещи, которые вы могли бы сделать, чтобы место в памяти:

  1. Читать это
  2. Написать это
  3. узнавать адрес

Элементы 1 и 2 (чтение и запись) составляют разыменования. Пункт 3, однако, не является разыменованием, поскольку память по конкретному адресу недоступна.

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

+0

Это имеет смысл. Я попробовал следующее и предоставленные вами разъяснения правильно: int * b = NULL; printf ("\ nAddress of b is% p \ n", &(*b)); // NO SEGFAULT printf ("\ nАдрес b является% p, а val -% d \ n", & (* b), * b); // SEG FAULT – maverick

+0

@Adam Martin Спасибо за ссылку, она содержит подробную информацию о том, что я искал. – maverick

+0

Ваше редактирование сделало его еще более понятным. Это объяснение, которое я надеялся найти. – maverick

 Смежные вопросы

  • Нет связанных вопросов^_^