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 + a
⇔x = y - a
,
- 从常量减法:
y = c - x
⇔ x = c - y
,包括简单的否定 (c
= 0),
- 异或:
y = x ^ p
⇔x = y ^ p
,包括~x
(即x ^ 0xFF
),
- 在一些情况下乘以一个常数(奇数),但逆不明显。
对像 y = -((x + 0x17) ^ 0x15)
这样的复合进行逆向操作看起来像 x = ((-y) ^ 0x15) - 0x17
,请注意撤消步骤的相反顺序。
另一方面,这些是不可逆的:
- 和,
- 或者,
- 乘以偶数,
- 移位,
- 等等
有时您可以找到 反函数,如果这对您可行的话。这里如果保证input
在0
和18
之间(即0x90 / 8
),可以试试
uint8_t input = 10;
uint8_t output = 0x90 - (input * 8); // spot two differences
uint8_t newInput = (0x90 - output) / 8;
但是如果 input
更大,例如 20,它会给出一些恰好产生相同 output
.
的其他值
有几个问题导致您的代码无法运行,让我解释其中的一些问题:
- 您有一个无符号的 8 位整数,因此您可以使用 0x00 和 0xFF 之间的值。
0x190 - (10 *8) = 0x190 - 0x50 = 0x140
可以完成,但之后您用 &FF 删除了前导 1,因此您丢失了之后无法恢复的信息。
| FF
是按位或,它将计算的每一位都变成 1,因此无论输出如何,您总是会得到 0xFF = 255
。
- 你的计算有误。
- 在一次计算中使用十进制数 (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
这里有几点:
- 您似乎在尝试使用
& 0xFF
截断为 8 位,您应该取消它,因为标准已经保证无符号整数会发生这种情况:
- 您应该
(0x190 - output) / 8U
来恢复输入,所以即使大小允许,您的数学也是错误的:
o = 400 - 8x
o - 400 = -8x
(o - 400) / -8 = x
- 400 二进制是
0b1'1001'0000
所以由于向下转换截断了最高有效位它可能会也可能不会被设置,因此你总是有 2 个可能的答案(其中 output
是肯定的) :
const uint8_t newInputSmall = (0x190 - (output | 0b1'0000'0000)) / 8U;
cosnt uint8_t newInputLarge = (0x190 - output) / 8U;
- 您需要处理
output
为负数的可能性,因为 input * 8U
大于 400
我得到了以下操作:
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 + a
⇔x = y - a
, - 从常量减法:
y = c - x
⇔x = c - y
,包括简单的否定 (c
= 0), - 异或:
y = x ^ p
⇔x = y ^ p
,包括~x
(即x ^ 0xFF
), - 在一些情况下乘以一个常数(奇数),但逆不明显。
对像 y = -((x + 0x17) ^ 0x15)
这样的复合进行逆向操作看起来像 x = ((-y) ^ 0x15) - 0x17
,请注意撤消步骤的相反顺序。
另一方面,这些是不可逆的:
- 和,
- 或者,
- 乘以偶数,
- 移位,
- 等等
有时您可以找到 反函数,如果这对您可行的话。这里如果保证input
在0
和18
之间(即0x90 / 8
),可以试试
uint8_t input = 10;
uint8_t output = 0x90 - (input * 8); // spot two differences
uint8_t newInput = (0x90 - output) / 8;
但是如果 input
更大,例如 20,它会给出一些恰好产生相同 output
.
有几个问题导致您的代码无法运行,让我解释其中的一些问题:
- 您有一个无符号的 8 位整数,因此您可以使用 0x00 和 0xFF 之间的值。
0x190 - (10 *8) = 0x190 - 0x50 = 0x140
可以完成,但之后您用 &FF 删除了前导 1,因此您丢失了之后无法恢复的信息。 | FF
是按位或,它将计算的每一位都变成 1,因此无论输出如何,您总是会得到0xFF = 255
。- 你的计算有误。
- 在一次计算中使用十进制数 (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
这里有几点:
- 您似乎在尝试使用
& 0xFF
截断为 8 位,您应该取消它,因为标准已经保证无符号整数会发生这种情况: - 您应该
(0x190 - output) / 8U
来恢复输入,所以即使大小允许,您的数学也是错误的:
o = 400 - 8x
o - 400 = -8x
(o - 400) / -8 = x
- 400 二进制是
0b1'1001'0000
所以由于向下转换截断了最高有效位它可能会也可能不会被设置,因此你总是有 2 个可能的答案(其中output
是肯定的) :
const uint8_t newInputSmall = (0x190 - (output | 0b1'0000'0000)) / 8U;
cosnt uint8_t newInputLarge = (0x190 - output) / 8U;
- 您需要处理
output
为负数的可能性,因为input * 8U
大于 400