Лучший способ отделить длинные / короткие от байтового массива
Поэтому я строю шорты / длинные позиции на основе байтовых массивов, и я хотел бы избежать использования memcpy
скопировать байты в их собственную переменную, а затем присвоить эту переменную sockaddr_in
объект.
Есть ли лучший способ извлечь short
в следующем утверждении?:
((sockaddr_in*)from)->sin_port = (*((unsigned short*)&buf[4]));
Я сделал весь указатель / разыменование, потому что, если моя логика верна, делать только (unsigned short)buf[4]
приведение преобразует только один байт; не оба.
РЕДАКТИРОВАТЬ: Endianness в порядке. Я просто хочу, чтобы buf[4] и buf[5] были вместе в одном коротком замысле простым способом, кроме необходимости использовать memcpy
,
3 ответа
Код в вашем вопросе:
(*((unsigned short*)&buf[4]))
может не работать из-за следующих проблем:
memcpy
безопасно, если вы уверены в порядке байтов (если нет, то вы должны сочетать с ntohs
или же ntohl
). Приличный компилятор также должен оптимизировать его.
Если вы действительно хотите избежать memcpy
, то безопасный, независимый от платформы способ - это что-то вроде следующего (при условии, что buf
изначально был заполнен из внешнего источника, используя стандартный сетевой порядок байтов):
((buf[n] << 8) | buf[n+1])
Конечно, вы должны заключить это в функцию (или макрос, если необходимо).
Я думаю, что правильным решением будет при любых обстоятельствах использовать такие функции, как ntohs
а также htons
(за long
использование ntohl
а также htonl
).
((sockaddr_in*)from)->sin_port = htons(*((unsigned short*)&buf[4]));
Также имейте в виду, что в зависимости от источника вашего байтового массива вы можете столкнуться с дополнительными проблемами Endianess.
Выравнивание может быть другой проблемой на некоторых архитектурах (HP-RISC, SPARC). Функции memcpy
а также memmove
обычно таких проблем нет. И не стоит оптимизировать преждевременно!
Вы можете использовать макрос ntohs для обработки преобразования порядка байтов, htons означает порядок хост-сеть
((sockaddr_in*)from)->sin_port = htons(*((uint16_t*)&buf[4]));
Обратите внимание, что, однако, некоторые архитектуры не разрешают доступ без выравнивания, поэтому вам необходимо убедиться, что он выровнен, или вам может потребоваться извлечь выровненные байты во временную переменную и соответствующим образом перемешать биты.