C-указательная арифметика без объекта структуры
Я думаю, что это невозможно в C, но попросите проверить это. Можно ли сделать арифметику между членами структуры без реальной переменной этого типа? Например:
typedef struct _s1
{
int a;
int b;
int c;
} T1;
Я хочу видеть смещение члена "c" по сравнению с началом структуры. Это легко, если у меня есть переменная:
T1 str;
int dist = (int)&str.c - (int)&str;
Но моя структура слишком велика и у нее нет члена в ОЗУ (только в EEPROM). И я хочу сделать некоторые вычисления адресов, но не определять член RAM. Я могу выполнить работу со указателем структуры вместо переменной структуры (она будет стоить всего 4 байта), но случай интересен для меня.
Ответы
Ответ 1
Используя offsetof, вы можете делать вычисления между членами без необходимости перехватывать переменную этого типа. Все, что вам нужно, это сам тип и имя члена.
Замечание о том, что простые вычисления, скорее всего, не сработают: выравнивание данных. Вы не знаете, сколько добавлений ваш компилятор собирается бросить в вашу структуру, и это может привести к очень тонким ошибкам или сделать неправильные вычисления неправильными, если вы измените структуру.
Ответ 2
Во-первых, вы отправляете отдельные адреса на int
s. Я не думаю, что такая хорошая идея. a int
гарантированно имеет размер не менее 2 байтов или более, адрес/указатель обычно составляет 4 или 8 байтов. Отбросить их до int
просто не подходит. Если бы я их бросил, я бы использовал unsigned long
для 32-битных систем и unsigned long long
для 64 бит. Я бы использовал последний, чтобы быть в безопасности.
Тем не менее, я бы вообще не писал адреса и просто использовал макрос offsetof
.
Добавьте #include <stddef.h>
в свой файл и используйте макрос offsetof
, который задает значение смещения size_t
, а не int
, заметьте. Он работает просто, используя 0 в качестве адреса памяти структуры, а затем возвращает адрес данного члена, давая фактическое смещение:
size_t offset = offsetoff(T1, c);
//struct, member
Как заметил Зак в своем комментарии, следующая часть ответа несколько неактуальна, но для ссылок, которые она содержит, и для полноты я просто оставлю это здесь, так как offsetof
требуется от всех реализации:
Определите макрос самостоятельно, если у вас нет stddef.h по какой-либо причине (что должно было бы быть, потому что offsetof
уже некоторое время был частью стандарта: C89 и выше):
#ifndef offsetof
#define offsetof(s, m) ((size_t)&(((s *) 0)->m))
#endif
Это должно сделать трюк, но будьте осторожны: эта реализация может вызвать поведение undefined. Как и почему объясняется здесь
Я взял определение offsetof
выше из источник stddef.h, который я нашел здесь, поэтому вы можете просто загрузить этот файл и использовать он вместо определения макроса в вашем собственном файле, но имейте в виду, что используемый вами offsetof
не является на 100% надежным.
В любом случае, этого достаточно сейчас, больше информации о Google, но здесь несколько ссылок:
Ответ 3
Вы можете использовать offsetof
, определенный в stddef.h
.
Я знаю, что это выходит за рамки того, что вы просили, но есть одно интересное использование offsetof
, используемое, например, в коде ядра linux, макросе container_of
. container_of
может вернуть вам адрес родительской структуры, указав указатель на один из его членов:
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
Что вы можете использовать, например:
// pointer_to_c points to a member of the struct, c in this case
// and you want to get the address of the container
T1 *container;
container = container_of(pointer_to_c, T1, c);
Ответ 4
stddef.h
имеет макрос, называемый offsetof, который дает смещение члена от начала структуры.
size_t t = offsetof( T1 , c ) ;
Таким образом, вам не нужно фактически объявлять какие-либо структурные переменные.
Ответ 5
Взгляните на Выравнивание структуры данных
Правильно:
size_t dist = offsetof(struct _s1, c);
Ответ 6
В заголовке stddef.h
имеется макрос; offsetof
. Вы можете использовать его в своей структуре следующим образом:
int dist = (int)offsetof(T1, c);