正确解释有符号与无符号
Correct interpretation signed vs unsigned
我从通信中接收到 2 个字节,然后我需要合并这 2 个值以获得 16 位值。
现在假设我希望收到200这个数字,那么这两个字符就是a和b
char a=0x00;
char b=0xc8;
int cw = (a << 8) | b ;
printf("cw= %d\n",cw);
合并后变量 cw 变为 -56 而不是 200
如果我用 unsigned char 改变 char 我得到正确的值 200
我该如何解决?我希望收到正数和负数,当然还有数字 200
您应该做的唯一更改是定义无符号的最低有效字节:
char a;
unsigned char b;
... // receive a and b from your communication
int cw = (a << 8) | b;
printf("cw = %d\n", cw);
arithmetic/logic 表达式应该可以工作,但要解释它为什么不溢出可能并不简单,因为它涉及将 char
或 unsigned char
提升为 int
(我猜你的系统是 16 位的)。
如果您希望代码可移植(即不假设 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);
但是这段代码的可读性较差,所以我不确定这里更便携有什么优势。
16 bit value.
只要使用正确的类型。
unsigned char a = 0x00;
unsigned char b = 0xc8;
int16_t cw = ((unsigned int)a << 8) | b;
C 标准基本上没有提供将 1 位移入或移出符号位置的方法(<<
唯一定义的情况是针对不会溢出的非负值)并且没有明确的方法将无符号值转换为负值(将超出范围的值转换为有符号整数类型是实现定义的)。
所以我们不应该使用轮班。然而,负值的乘法当然是有定义的,所以我们可以使用:
int8_t a;
uint8_t b;
// Put code here to receive a and b by some method.
uint16_t cw = a*256 + b;
如果您必须从无符号类型重建有符号整数,那么一个选项是测试符号位并手动应用二进制补码:
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 += -128*256; // If sign bit is set, adjust.
您还可以复制以下位:
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);
(以上假定您的 16 位整数使用二进制补码。)
我从通信中接收到 2 个字节,然后我需要合并这 2 个值以获得 16 位值。
现在假设我希望收到200这个数字,那么这两个字符就是a和b
char a=0x00;
char b=0xc8;
int cw = (a << 8) | b ;
printf("cw= %d\n",cw);
合并后变量 cw 变为 -56 而不是 200
如果我用 unsigned char 改变 char 我得到正确的值 200 我该如何解决?我希望收到正数和负数,当然还有数字 200
您应该做的唯一更改是定义无符号的最低有效字节:
char a;
unsigned char b;
... // receive a and b from your communication
int cw = (a << 8) | b;
printf("cw = %d\n", cw);
arithmetic/logic 表达式应该可以工作,但要解释它为什么不溢出可能并不简单,因为它涉及将 char
或 unsigned char
提升为 int
(我猜你的系统是 16 位的)。
如果您希望代码可移植(即不假设 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);
但是这段代码的可读性较差,所以我不确定这里更便携有什么优势。
16 bit value.
只要使用正确的类型。
unsigned char a = 0x00;
unsigned char b = 0xc8;
int16_t cw = ((unsigned int)a << 8) | b;
C 标准基本上没有提供将 1 位移入或移出符号位置的方法(<<
唯一定义的情况是针对不会溢出的非负值)并且没有明确的方法将无符号值转换为负值(将超出范围的值转换为有符号整数类型是实现定义的)。
所以我们不应该使用轮班。然而,负值的乘法当然是有定义的,所以我们可以使用:
int8_t a;
uint8_t b;
// Put code here to receive a and b by some method.
uint16_t cw = a*256 + b;
如果您必须从无符号类型重建有符号整数,那么一个选项是测试符号位并手动应用二进制补码:
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 += -128*256; // If sign bit is set, adjust.
您还可以复制以下位:
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);
(以上假定您的 16 位整数使用二进制补码。)