Дано:
char msb = 0x01 ;
char lsb = 0x02 ;
Тогда:
short word = (msb << 8) | (lsb & 0xff) ;
приведет к тому, что word
будет иметь значение 0x0102 (или 258 10 ).
Поскольку вы попросили подписать короткую заявку, это не очень интересный пример. Для:
char msb = 0x80 ;
char lsb = 0x02 ;
word
будет иметь 0x8002, что для 16-битного short
будет -32766.
Однако в реализации, где short
длиннее 16 бит (что разрешено), результат будет интерпретироваться как +32770. В этом случае гораздо безопаснее использовать тип int16_t
фиксированного размера, определенный в stdint.h
, чтобы избежать потенциальной зависимости от реализации.
int16_t word = (msb << 8) | (lsb & 0xff) ;
Это можно несколько упростить, используя uint8_t
вместо char
, который может быть либо подписанным, либо без знака:
uint8_t msb = 0x80u ;
uint8_t lsb = 0xFFu ;
int16_t word = (msb << 8) | lsb ;
Результатом будет word
= -32513, тогда как если бы lsb
и msb
были char
и char
были подписаны в реализации, то результатом было бы -1 из-за неявного продвижения типа и знака расширение lsb
.
Это остается не совсем четко определенным, поскольку левое выражение повышается до unsigned int
и может привести к значению, не представляемому как int16_t
, и в этом случае поведение определяется реализацией. Тем не менее, это была бы необычная реализация, которая делала что-то другое, а не просто копировала биты дословно, именно поэтому она работает, а вышесказанное идиоматично.
Если явно требуется short
, чтобы гарантировать правильно подписанный результат независимо от длины short
, вы можете явно привести к int16_t
и присвоить short
(или даже int
):
short word = (int16_t)((msb << 8) | (lsb & 0xFF));
Решение также возможно с использованием объединения, но, учитывая теги по этому вопросу, маловероятно, что это приемлемое решение в этом случае. Он имеет преимущество, заключающееся в том, что он избегает любого поведения, определенного реализацией, а также продвижения тайных типов и неявных правил преобразования, но вам приходится иметь дело с порядком байтов:
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define LSB 0
#define MSB 1
#else
#define LSB 1
#define MSB 0
#endif
union
{
int16_t word ;
uint8_t byte[2] ;
} reinterpret ;
reinterpret.byte[MSB] = 0x80u ;
reinterpret.byte[LSB] = 0xFFu ;
short word = reinterpret.word ;
https://onlinegdb.com/Byth1N3yr