подготовить и удалить из (void *) в C - PullRequest
1 голос
/ 07 декабря 2010

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

У меня есть функция, которая отправляет поток по сети. естественно, это принимает const void * в качестве аргумента:

void network_send(const void* data, long data_length)

Я пытаюсь добавить к этому определенный заголовок в виде символа * перед отправкой через сокет:

  long sent_size = strlen(header)+data_length;
  data_to_send = malloc(sent_size);
  memcpy(data_to_send,header,strlen(header)); /*first copy the header*/
  memcpy((char*)data_to_send+strlen(header),data,dat_length); /*now copy the actual data*/

Это прекрасно работает, пока данные на самом деле char *. но если он меняется на какой-то другой тип данных, то это перестает работать.

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

void network_data_received(const void* data, long data_length)
{
 ........
 memmove(data_from_network,(char*)data_from_network + strlen(header),data_length); /*move the data to the beginning of the array*/
 ProcessFurther(data_from_network ,data_length - strlen(header)) /*data_length - strlen(header) causes the function ProcessFurther to read only certain part of the array*/
}

Это снова работает нормально, если данные имеют тип char. но вылетает, если он любого другого типа.

Кто-нибудь может подсказать, как правильно это реализовать?

С уважением, Хан

Ответы [ 6 ]

2 голосов
/ 07 декабря 2010

Что-то удивляет меня в этом коде.Ваш заголовок на самом деле строка?Если это структура, для чего-то подобного вы должны заменить strlen на sizeof.Вызов strlen для строки, не заканчивающейся нулями, может вызвать сбои.

Второе, что меня удивляет, это то, что при чтении полученных данных вы должны где-то скопировать заголовок.Если он не используется, зачем отправлять его по проводам?

РЕДАКТИРОВАТЬ: ОК, заголовок представляет собой строку заголовка типа http.Оттуда не должно быть никаких проблем, и это действительно не нужно анализировать, если вы просто тестируете.

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

Если проблема возникает из-за выравнивания, она исчезнет, ​​если вы скопируете данные в некоторую переменную реального целевого типа на уровне байтов перед использованием.

Существует другое решение: выделить свой буферс malloc и поместите структуру данных, которую вы хотите в начале.Тогда вы должны быть в состоянии разыграть его.Адреса, возвращаемые malloc, совместимы с любым типом.

Также следует помнить, что если вы работали с C ++, приведение к нетривиальному классу вряд ли сработает (во-первых, vtables может получить неправильные адресаи есть другие проблемы).

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

2 голосов
/ 07 декабря 2010

Звучит так, что выравнивание может быть проблемой, но вы не указываете, на какой платформе вы это делаете (разные архитектуры ЦП предъявляют разные требования к выравниванию).

Если длина заголовка "неправильная" длявыравнивание следующих данных, которые могут привести к нарушениям доступа.

0 голосов
/ 09 декабря 2010

с помощью unsigned char * решил проблему. Спасибо всем за ваши комментарии.

0 голосов
/ 07 декабря 2010

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

0 голосов
/ 07 декабря 2010

Возможно, что data_length не правильно рассчитан в коде вызова. В противном случае, кажется, что этот код в порядке, кроме возможных проблем с выравниванием, упомянутых @unwind.

Как объявлено header? Имеет ли он переменную длину? Вам не хватает завершающего символа NUL после header?

0 голосов
/ 07 декабря 2010
Поведение

memcpy не определено, если источник и цель перекрываются (как в этом случае), которые вы должны использовать memmove()

Что именно происходит, когда что не char*? Эти функции обычно приводятся к void*, прежде чем выполнять какую-либо работу ...

...