Подтвердить что ты не робот

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 байта), но случай интересен для меня.

4b9b3361

Ответ 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 ) ;

Таким образом, вам не нужно фактически объявлять какие-либо структурные переменные.

Ответ 6

В заголовке stddef.h имеется макрос; offsetof. Вы можете использовать его в своей структуре следующим образом:

int dist = (int)offsetof(T1, c);