2016-02-07 6 views
7

Я новичок в языке C и только что узнал о структурах и указателях.Зачем нужен макрос offsetof?

Мой вопрос связан с макросом offsetof, который я недавно видел. Я знаю, как это работает, и логикой этого.

В файле <stddef.h> определение выглядит следующим образом:

#define offsetof(type,member) ((unsigned long) &(((type*)0)->member)) 

Мой вопрос, если у меня есть-структуру, как показано ниже:

struct test { 
    int field1: 
    int field2: 
}; 

struct test var; 

Почему я не могу сразу получить адрес field2 as:

char * p = (char *)&var; 
char *addressofField2 = p + sizeof(int); 

Вместо того, чтобы писать что-то вроде этого

field2Offset = offsetof (struct test, field2); 

а затем добавление значения смещения к стартовому адресу var?

Есть ли разница? Использует ли offsetof более эффективный?

+0

Если вы новичок в C, отпустите 'offsetof' и тому подобное. Вам не понадобится это для нормального программирования, но только расширенные функции новичка, скорее всего, испортится. - Ночь, но очень хорошее предупреждение! – Olaf

ответ

4

Компилятор C часто добавляет дополнительные биты заполнения или байты между членами struct, чтобы повысить эффективность и сохранить целые слова с выравниванием по словам (что в некоторых архитектурах необходимо избегать bus errors и в некоторых архитектурах требуется для избежания эффективности проблемы). Например, во многих компиляторах, если у вас есть этот struct:

struct ImLikelyPadded { 
    int x; 
    char y; 
    int z; 
}; 

вы можете обнаружить, что sizeof(struct ImLikelyPadded) является 12, а не 9, потому что компилятор будет вставить три дополнительных байта отступов между концом одного байта char y и размер слова int z. Вот почему offsetof настолько полезен - он позволяет вам определить, где вещи действительно даже факторизуются в байтах заполнения и очень переносимы.

+1

В дополнение, единственная причина, по которой реализация уходит с UB в макросе, заключается в том, что она * является * реализацией. – Deduplicator

0

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

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

Смещение, макрос, позволяет узнать расстояние, смещение, члена структуры из позиции расположения структуры.

Одно интеллектуальное использование, если offsetof видно в макросе ядра Linux container_of. Этот макрос позволяет узнать начальную позицию узла с адресом адреса в общем сводном двусвязном списке.

0

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

Еще одна веская причина использовать макрос offsetof, а не вручную вычислять смещения, заключается в том, что вам нужно только написать его один раз. Представьте, что произойдет, если вам нужно изменить тип field1 или вставить или удалить одно или несколько полей перед field2. Используя ваш ручной расчет, вы должны найти и изменить все его события. Отсутствие одного из них вызовет загадочные ошибки, которые трудно найти.

Код, использованный с помощью offsetof не имеет необходимости в обновлениях. Компилятор позаботится обо всем на следующей компиляции.

Более понятный код, который использует offsetof. Макрос стандартный, его функциональность - documented. Один программист, который читает код, сразу понимает его. Не совсем понятно, что делает ручной код.

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

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