C ++如何将两个带符号的8位数字组合为一个16位的短路符?无法解释的结果

问题描述 投票:11回答:7

我需要将两个带符号的8位_int8值组合为一个带符号的短(16位)值。重要的是,不要丢失标志。

我的代码是:

 unsigned short lsb = -13;
 unsigned short msb = 1;
 short combined = (msb << 8 )| lsb;

我得到的结果是-13。但是,我希望它是499

对于以下示例,使用相同的代码可获得正确的结果:

msb = -1; lsb = -6; combined = -6;
msb = 1; lsb = 89; combined = 345; 
msb = -1; lsb = 13; combined = -243;

但是,我希望在msb = 1; lsb = -84; combined = -84;出现428

似乎如果lsb为负,而msb为正,则出问题了!我的代码有什么问题?计算机如何获得这些意外结果(Win7、64位和VS2008 C ++)?

c++ byte signed short
7个回答
22
投票

在这种情况下,您的lsb包含0xfff3。当您将其与1 << 8进行或运算时,没有任何变化,因为该位位置已经有1。

尝试short combined = (msb << 8 ) | (lsb & 0xff);


8
投票

或使用联合:

#include <iostream>

union Combine
{
    short target;
    char dest[ sizeof( short ) ];
};

int main()
{
    Combine cc;
    cc.dest[0] = -13, cc.dest[1] = 1;
    std::cout << cc.target << std::endl;
}

2
投票

[lsb可能被自动符号扩展为16位。我注意到,只有当它为负数且msb为正数时,您才有问题,这就是您使用or运算符的方式所期望的。虽然,您显然在这里做了很奇怪的事情。您实际上想在这里做什么?


1
投票

如果这是您想要的:

msb: 1, lsb: -13, combined: 499
msb: -6, lsb: -1, combined: -1281
msb: 1, lsb: 89, combined: 345
msb: -1, lsb: 13, combined: -243
msb: 1, lsb: -84, combined: 428

使用此:

short combine(unsigned char msb, unsigned char lsb) {
    return (msb<<8u)|lsb;
}

我不明白为什么您会希望msb -6和lsb -1生成-6。


1
投票

STM8的Raisonanse C编译器(可能还有许多其他编译器)在将16位变量写入8位硬件寄存器时,会生成经典C代码的难看代码。注意-STM8是big-endian,对于little-endian CPU,必须略微修改代码。读/写字节顺序也很重要。

因此,标准的C代码片段:

 unsigned int ch1Sum;
...
     TIM5_CCR1H = ch1Sum >> 8; 
     TIM5_CCR1L = ch1Sum; 

正在被编译为:

;TIM5_CCR1H = ch1Sum >> 8; 
         LDW   X,ch1Sum 
         CLR   A 
         RRWA  X,A 
         LD    A,XL 
         LD    TIM5_CCR1,A 
;TIM5_CCR1L = ch1Sum; 
         MOV   TIM5_CCR1+1,ch1Sum+1 

太长,太慢。

我的版本:

     unsigned int ch1Sum;
...
     TIM5_CCR1H = ((u8*)&ch1Sum)[0];
     TIM5_CCR1L = ch1Sum;

被编译成足够的两个MOV

;TIM5_CCR1H = ((u8*)&ch1Sum)[0]; 
       MOV   TIM5_CCR1,ch1Sum 
;TIM5_CCR1L = ch1Sum;
       MOV   TIM5_CCR1+1,ch1Sum+1 

相反方向:

    unsigned int uSonicRange;
...
      ((unsigned char *)&uSonicRange)[0] = TIM1_CCR2H;
      ((unsigned char *)&uSonicRange)[1] = TIM1_CCR2L;

代替

    unsigned int uSonicRange;
...
      uSonicRange = TIM1_CCR2H << 8;
      uSonicRange |= TIM1_CCR2L;

1
投票

关于数据类型(unsigned shortchar

,您应该了解的一些知识”

char是一个8位值,这就是您要查找lsbmsb的地方。 short的长度为16位。

您也不应在知道自己在做什么的execpt中存储signed值。您可以看一下the two's complement。它描述了C / C ++和许多其他编程语言中负值的表示(对于整数,不是浮点值)。

有多种版本来制作自己的二进制补码:

int a; // setting a a = -a; // Clean version. Easier to understand and read. Use this one. a = (~a)+1; // The arithmetical version. Does the same, but takes more steps. // Don't use the last one unless you need it! // It can be 'optimized away' by the compiler.


stdint.h (with inttypes.h)的目的更多是为了使变量具有精确的长度。如果您确实需要一个变量来具有特定的字节长度,则应该使用该变量(在这里需要它)。

您应该每个人都使用最适合您的数据类型。因此,您的代码应如下所示:

signed char lsb; // signed 8-bit value signed char msb; // signed 8-bit value signed short combined = msb << 8 | (lsb & 0xFF); // signed 16-bit value

或类似这样:

#include <stdint.h> int8_t lsb; // signed 8-bit value int8_t msb; // signed 8-bit value int_16_t combined = msb << 8 | (lsb & 0xFF); // signed 16-bit value

对于最后一个,无论平台上的长度[[int
为何,编译器每次都会使用带符号的8/16位值。 Wikipedia

int8_t和int16_t数据类型(以及所有其他数据类型)有了很好的解释。btw:cppreference.com可用于查找ANSI C标准和其他有关C / C ++的知识。


0
投票
© www.soinside.com 2019 - 2024. All rights reserved.