void * проблема присваивания - PullRequest
1 голос
/ 07 октября 2010

Я хочу взять некоторые поля из структуры пакета, используя указатель arithmetic. Но что не так с кодом ниже?
В первом случае я думаю, что если я иду 4 байта (2 коротких поля) от начала пакета, я получаю tLow.Но это не дает ожидаемого значения. Кроме того, во втором случае я хочу получить поле данных, пройдя 12 байт от начала пакета. Что не так с моей идеей?

struct packet{  
      short len;
      short field;
      int tLow;
      int tHigh;
      void *data;
}

int main()
{
    struct packet pack;
    struct packet *pck;

    pack.len=3;
    pack.field=34;
    pack.tLow=712;
    pack.tHigh = 12903;
    pack.data = "message";

    pck = &pack;
    int *timeLow = (int * )pck + 4; // i want to get tLow 
    printf("Time Low :%d\n",*time);

    char *msg = (char *)pck + 12 ;// want data 
    printf("Message :%s\n",msg);

    return 0;
}

Ответы [ 6 ]

3 голосов
/ 07 октября 2010

Вам определенно было бы лучше использовать стандартный метод

int *timeLow = &(pck->tLow);

Компиляторам разрешено вставлять байты заполнения между любыми элементами структуры.Правила для этих байтов заполнения, в лучшем случае, определяются реализацией ... поэтому вы должны обратиться к руководству по реализации, чтобы быть уверенным, как (или если) и сколько байтов вставлено в ваш конкретный случай.Также обратите внимание, что число байтов заполнения может меняться от компиляции к компиляции с разными параметрами или от компилятора к компилятору (компьютер на компьютер, ...)

Вы можете попробовать использовать макрос C offsetofно это не красиво:

size_t offset = offsetof(struct packet, tLow);
/* make sure offset is a multiple of sizeof (int*) */
int *timeLow = (int*)pck + offset / sizeof (int*);

или, чуть менее уродливо, используя приведение к (char*) и копируя код из других ответов : -)

size_t offset = offsetof(struct packet, tLow);
int *timeLow = (int*)((char*)pck + offset);

Oh!и в вашем источнике отсутствует точка с запятой

2 голосов
/ 07 октября 2010

В основном вы полагаетесь на неопределенное поведение.Выравнивание структуры и т. Д. Но в любом случае ...

(int *) pck + 4. Продвинет указатель 4 * sizeof (int).Это неправильно, мы хотим увеличить его на 1, если предположим, что структура упакована и sizeof (short) == 2, таким образом ...

int *timeLow = (int * )pck + 1; // i want to get tLow 
printf("Time Low :%d\n",*timeLow);

выводит правильный результат.

Что касается сообщения, вам нужно сделать что-то грязное.Поскольку я на x86_64, компилятор решил заполнить void * на 8-байтовых границах, поэтому смещение составило 16, а не ожидаемое 12.

Мы в основном получаем указатель на void *.Таким образом, код будет выглядеть следующим образом:

char **msg = (char**)((char *)pck + 16) ;// want data 
printf("Message :%s\n",*msg);

НИКОГДА напишите код, подобный этому, это просто иллюстрирует точку.

2 голосов
/ 07 октября 2010

Вы ищете offsetof .

Ваш код может выглядеть следующим образом:

int *timeLow = (int*) ((char*)pck + offsetof(struct packet, tLow);

и, как указал pmg,

int *timeLow = &(pck->tLow);

- это канонический способ получения указателя на член структуры.

Этот ответ также принес арифметику указателя на таблицу - которую я узнал сегодня благодарядо вечера.

1 голос
/ 07 октября 2010

когда вы пишете

int *timeLow = (int * )pck + 4

, вы воспринимаете 'pck' как указатель типа int, который в зависимости от вашей системы может составлять 4 или 8 байтов.Это не будет корректно смещаться в структуру, потому что вы говорите, что она имеет смещение 4 int

, вместо этого вам нужно будет сделать вот так

int *timeLow = (int*)((short * )pck + 2); 
0 голосов
/ 07 октября 2010

Это неправильно: pack.data = "message"; Вы используете нераспределенную память.

Также это: int *timeLow = (int * )pck + 4; не гарантированно работает (выравнивание структуры зависит от компиляторов и систем).

0 голосов
/ 07 октября 2010

Шорты не обязательно имеют длину 2 байта. Все, что указано, это то, что они меньше или равны размеру целых. Вы, вероятно, должны использовать sizeof ()

...