2010-12-07 4 views
1

Я думаю, что это довольно прямая проблема, но я до сих пор не могу понять это.добавить и удалить из (void *) в C

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

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

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

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

+0

Как вы называете эти функции? Можете ли вы предоставить код? – detunized

+2

Вы не используете data_length, используя 'strlen', не так ли? Это действительно правильная функция для вашего заголовка? – Rup

+0

проблема заключается в использовании (char *) data_to_send + strlen (header) –

ответ

0

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

0

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

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

+0

, когда это не char *, оно все еще работает, но на приемном конце он перепутался. потому что данные зашифрованы (очень простое шифрование XOR). В принципе, здесь есть два типа данных: char * неподписанный * , поэтому я считаю, что мне нужно отличить void * от какого-то типа, который работает для них обоих. мой knowlefge в C++ ограничен из-за отсутствия его использования. –

2

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

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

+0

выравнивание - это проблема infact, потому что иногда я получаю недопустимый доступ к памяти, когда данные имеют неподписанный тип *. –

2

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

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

EDIT: ОК, заголовок представляет собой некоторую HTTP-строку заголовка. Там не должно быть никаких проблем, и это действительно не нужно анализировать, если вы просто проверяете.

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

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

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

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

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

+0

Заголовок: static const char * header = "GET /images/logo.gif \ r \ n HTTP/1.1. \ R \ n Принять: /. \ R \ n Referrer: google.com. \ R \ n Accept-Language: en-us. \ R \ n Данные: « –

0

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

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

+0

заголовок объявлен следующим образом: static const char * header =" GET /images/logo.gif \ r \ n HTTP/1.1. \ R \ n Accept: */*. \ R \ n Referrer: http://www.google.com/. \ R \ n Accept-Language: en-us. \ R \ n Данные: "; постоянная длина 122. заголовок infact не является проблемой, конверсия в (char *) вызывает проблему –

0

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