В Руководство Биджа по сетевому программированию, есть функция, предназначенная для обеспечения переносимого способа сериализации 16-разрядного целого числа.
/*
** packi16() -- store a 16-bit int into a char buffer (like htons())
*/
void packi16(unsigned char *buf, unsigned int i)
{
*buf++ = i>>8; *buf++ = i;
}
Я не понимаю, почему заявление *buf++ = i;
является переносимым, как назначение целого без знака (i
) без знака (*buf
) приведет к сужению конверсии.
unsigned int
всегда усекается, и его младшие 8 бит сохраняются в unsigned char
?Если нет, есть ли какой-либо предпочтительный способ решить проблему? Достаточно ли изменить тело функции на следующее?
* buf ++ = (i >> 8) & 0xFFFFU; * buf ++ = я & 0xFFFFU;
Код предполагает 8-битный байт, и он не является переносимым.
Например. некоторые цифровые сигнальные процессоры Texas Instruments имеют 16-битный байт.
Количество бит на байт определяется как CHAR_BIT
от <limits.h>
,
Кроме того, код предполагает, что unsigned
16 бит, который не является переносимым.
В итоге код не является переносимым.
ре
» Гарантирует ли стандарт C ++, что в таком преобразовании беззнаковое int всегда усекается, а его младшие 8 бит остаются в беззнаковом символе?
Нет, поскольку стандарт C ++ не гарантирует, что число бит на байт равно 8.
Единственная гарантия, что это по крайней мере 8 бит
Арифметика без знака гарантированно модульна.
ре
Если нет, есть ли какой-нибудь предпочтительный способ решить проблему?
Используйте простой цикл, повторяющийся sizeof(unsigned)
раз.
Код, о котором идет речь, похоже, был извлечен из такого цикла, так как постинкремент в *buf++ = i;
совершенно бессмысленно (это последнее использование buf
).
Да, присваивания вне диапазона типам без знака корректируют значение по модулю на единицу больше максимального значения, представляемого в типе. В этом случае мод UCHAR_MAX+1
,
Исправление не требуется. Некоторые люди любят писать *buf++ = i % 0x100;
или эквивалент, чтобы прояснить, что это было намеренное сужение.