简体   繁体   English

正确解释有符号与无符号

[英]Correct interpretation signed vs unsigned

I'm receiving 2 bytes from a communication and then i need to merge these 2 values to obtain a 16 bit value.我从通信中接收 2 个字节,然后我需要合并这 2 个值以获得 16 位值。

Now suppose that I expect to receive the number 200, then the two characters are a and b现在假设我期望收到数字 200,那么这两个字符是ab

char a=0x00;
char b=0xc8;
int  cw = (a << 8) | b ;
printf("cw= %d\n",cw);

Doing the merge the variable cw becomes -56 instead of 200进行合并,变量 cw 变为 -56 而不是 200

If i change char by unsigned char i got the correct value 200 How can i fix that?如果我用 unsigned char 更改 char 我得到了正确的值 200 我该如何解决这个问题? i expect to receive both positive and negative numbers and of course the number 200我希望收到正数和负数,当然还有数字 200

16 bit value. 16 位值。

Just use proper type.只需使用正确的类型。

unsigned char a = 0x00;
unsigned char b = 0xc8;
int16_t cw = ((unsigned int)a << 8) | b;

The only change you should do is defining the least significant byte unsigned:您应该做的唯一更改是定义无符号的最低有效字节:

char a;
unsigned char b;
... // receive a and b from your communication
int cw = (a << 8) | b;
printf("cw = %d\n", cw);

The arithmetic/logic expression should work, but it may be non-trivial to explain why it doesn't overflow, because it involves promotion of char or unsigned char to int (which, I guess, is 16-bit on your system).算术/逻辑表达式应该可以工作,但解释它为什么不溢出可能并非易事,因为它涉及将charunsigned char提升为int (我猜,在您的系统上是 16 位)。

If you want your code to be portable (ie not assume 16-bit int or any other property of your specific platform), use integers with defined size, and do explicit casting.如果您希望您的代码是可移植的(即不假定 16 位int或您特定平台的任何其他属性),请使用具有定义大小的整数,并进行显式转换。

int8_t a;
uint8_t b;
... // receive a and b from your communication
int16_t cw = (int16_t)((int16_t)a << 8) | (int16_t)b;
printf("cw = %d\n", (int)cw);

But this code is less readable, so I am not sure being more portable has any advantage here.但是这段代码的可读性较差,所以我不确定更便携有什么优势。

The C standard essentially provides no way to shift a 1 bit into the sign position (the only defined cases for << are for non-negative values) and no definite way to convert an unsigned value to a negative value (conversions of out-of-range values to signed integer types are implementation-defined). C 标准基本上没有提供将 1 位移入符号 position 的方法( <<的唯一定义情况是针对非负值),也没有明确的方法将无符号值转换为负值(out-of 的转换) -范围值到有符号的 integer 类型是实现定义的)。

So we should not use a shift.所以我们不应该使用班次。 However, multiplication of negative values is of course defined, so we can use:但是,负值的乘法当然是定义的,所以我们可以使用:

int8_t  a;
uint8_t b;
// Put code here to receive a and b by some method.
uint16_t cw = a*256 + b;

Another option is to test the sign bit and apply the two's complement manually:另一种选择是测试符号位并手动应用二进制补码:

unsigned char a, b;
// Put code here to receive a and b by some method.
int cw = (a & 0x7f) << 8 | b;  // Assemble the low 15 bits.
if (a & 0x80)
    cw -= 0x8000;              // If sign bit is set, adjust.

We can also copy the bits in:我们还可以将这些位复制到:

unsigned char a, b;
// Put code here to receive a and b by some method.
int16_t cw;
memcpy(&cw, (uint16_t []) { (uint16_t) a << 8 | b }, sizeof cw);

(The above presume your 16-bit integer uses two's complement.) (以上假设您的 16 位 integer 使用二进制补码。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM