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、10 或 42 的 output,预期 return 是什么?这个没有办法。如果您想要原始的 input,则需要在某处保留该变量的副本。

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

  • 常量的加法和减法:y = x + ax = y - a,
  • 从常量减法:y = c - xx = c - y,包括简单的否定 (c = 0),
  • 异或:y = x ^ px = 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 是按位或,它将计算的每一位都变成 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 位,您应该取消它,因为标准已经保证无符号整数会发生这种情况:
  2. 您应该 (0x190 - output) / 8U 来恢复输入,所以即使大小允许,您的数学也是错误的:

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

  1. 400 二进制是 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