繁体   English   中英

C ++按位反向运算

[英]C++ bitwise operation reverse

我得到以下操作:

uint8_t input = 10;
uint8_t output = ((0x190 - (input * 8)) & 0xFF);

// newInput should be 10 again, but is 255
uint8_t newInput = (((output * 8) + 0x190) | 0xFF);

我该如何纠正操作设置newInput ,使其返回10?

您想反转从input获得output的转换,但是不幸的是逻辑存在缺陷。 | 不是&的倒数, * 8绝对不是另一个* 8倒数。 另外,如果您想反转y = 0x190 - x ,则它不是+ ,而是另一个x = 0x190 - y (在纸上尝试!)最后,如果所有操作都正确,则命令的顺序为了撤消操作,操作需要颠倒(先进先出)。

实际上,您的转换不能倒置,因为它会丢失定义input部分信息。 (从数学上讲,它不是单射的。)请考虑:

uint8_t input = 10;
uint8_t output = ((0x190 - (input * 8)) & 0xFF); /* 0x40 */

uint8_t input2 = 42;
uint8_t output2 = ((0x190 - (input2 * 8)) & 0xFF); /* also 0x40! */

如果您有一个可以撤消该操作的函数,那么对于0x40或42的output将会返回什么? 这没有解决办法。 如果您想要原始input ,则需要将该变量的副本保存在某个地方。

在无符号8位计算中可以撤消的操作示例如下:

  • 常数的加法和减法: y = x + a a⇔x x = y - a
  • 从常数中减去: y = c - x x⇔x x = c - y ,包括纯否定( c = 0),
  • XOR: y = x ^ p p⇔x x = y ^ p ,包括~x (即x ^ 0xFF ),
  • 某些情况下(通过奇数)乘以常数,但反作用并不明显。

对类似于y = -((x + 0x17) ^ 0x15)的化合物进行逆运算将看起来像x = ((-y) ^ 0x15) - 0x17 ,请注意步骤的相反顺序。

另一方面,这些不是不可逆的:

  • 和,
  • 要么,
  • 乘以偶数,
  • 位移
  • 等等

有时,您可以找到一个逆函数,如果这对您来说可行。 在这里,如果保证input018之间(即0x90 / 8 ),则可以尝试

uint8_t input = 10;
uint8_t output = 0x90 - (input * 8); // spot two differences
uint8_t newInput = (0x90 - output) / 8;

但是,如果input较大,例如20,它将提供可能产生相同output其他值。

为什么您的代码无法正常工作有几个问题,让我解释其中的一些问题:

  1. 您有一个无符号的8位整数,因此可以使用0x00到0xFF之间的值。 0x190 - (10 *8) = 0x190 - 0x50 = 0x140可以完成,但是之后您用&FF切掉了前导1,因此您丢失了以后无法恢复的信息。
  2. | FF | FF是按位或,它将计算的每一位变为1,因此无论输出如何,您始终将获得0xFF = 255
  3. 您的计算是错误的。
  4. 在一次计算中使用十进制数(10)和十六进制数(0x190)是危险的。 可能会造成混乱。

我建议确保您不会使变量溢出。 使用其他常量,这样您就可以保持在unit8_t范围内,或者使用其他类型(如int16_t)也不会溢出这些小数字。 注意您的按位运算符。 就像我说的那样,最后一个OR将始终使newInput = 255。

这是一个适用于给定参数的示例:

int16_t input = 10; // int16_t wont overflow
int16_t output = ((0x190 - (input * 8)) ); // without &FF there is no
                                            // loss of information

int16_t newInput = (0x190- output) / 8; // Reshape of the line obove

这里有几点:

  1. 您似乎正在尝试使用& 0xFF截断为8位,您应该摆脱它,因为该标准已经保证了无符号整数会发生这种情况: https : //stackoverflow.com/a/36234166/2642059
  2. 您应该这样做(0x190 - output) / 8U以恢复输入,所以即使允许的大小您的数学也是错误的:

o = 400-8倍
o-400 = -8x
(o-400)/ -8 = x

  1. 二进制中的400是0b1'1001'0000因此,因为0b1'1001'0000截断了最高位,所以可能会且可能不会将其置位,因此您将始终有2个可能的答案( output为正):
const uint8_t newInputSmall = (0x190 - (output | 0b1'0000'0000)) / 8U;
cosnt uint8_t newInputLarge = (0x190 - output) / 8U;
  1. 您需要处理output为负的可能性,因为input * 8U大于400

暂无
暂无

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

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