我正在逆向工程一些旧的C,在Win95下运行(是的,在生产中)似乎是用Borland编译器编译的(我没有工具链)。
有一个功能可以做(除此之外)这样的事情:
static void unknown(int *value)
{
int v = *value;
v-=0x8000;
*value = v;
}
我无法弄清楚这是做什么的。我假设在这种情况下'int'是32位的签名。我认为0x8000将是无符号的32位int,并且在有符号的32位int的范围之外。 (编辑 - 这是错误的,它在签名的16位int之外)
我不确定是否会先抛出其中一个,以及铸件如何处理溢出,和/或减法如何处理溢出。
我可以尝试使用现代系统,但我也不确定结果是否相同。
为清晰起见编辑:
1:'v- = 0x8000;'直接来自原始代码,这对我来说没什么意义。 v定义为int。
2:我有代码,这不是来自asm。
3:原始代码非常非常糟糕。
编辑:我有答案!下面的答案不是很正确,但它让我在那里(修好,我会把它标记为答案)。v中的数据来自一个模糊的源,实际上似乎是发送无符号 16位数据,但它被存储为有符号的int。在程序中进行后,所有值都转换为浮点数并归一化为平均0点,因此实际值无关紧要,只有顺序。因为我们将unsigned int看作有符号的,所以超过32767的值被错误地放在0以下,所以这个hack将值保留为signed,但是交换负数和正数(不改变顺序)。最终结果是所有数字具有相同的顺序(但不同的值),就好像它们首先是无符号的一样。
(...这不是本程序中最糟糕的代码示例)
答案 0 :(得分:3)
在Borland C 3.x中,int
和short
是相同的:16位。 long
是32位。
十六进制文字具有可以表示值的第一种类型:int
,unsigned int
,long int
或unsigned long int
。
对于Borland C,0x8000
是十进制值32768,不适合int
,但会在unsigned int
中。所以unsigned int
就是。
声明v -= 0x8000 ;
与v = v - 0x8000 ;
在右侧,int
值v
被隐式转换为unsigned int
,根据规则,执行算术运算,产生rval
是unsigned int
。然后,unsigned int
再次按照规则隐式地返回lval
的类型。
所以,根据我的估计,净效应是切换符号位 - 通过简单的比特操作可以更容易和清楚地完成:*value ^= 0x8000 ;
。
答案 1 :(得分:1)
此页面上可能有线索http://www.ousob.com/ng/borcpp/nga0e24.php - Borland C ++ 2.x指南(使用Turbo C)
没有负数字常数这样的东西。如果 减号前面的数字常量被视为 一元减运算符,与常数一起, 构成数字表达式。这很重要 -32768,虽然它可以表示为int, 实际上有类型long int,因为32768类型为long。至 得到所需的结果,你可以使用(int)-32768, 0x8000,或0177777。
这意味着使用two's complement表示负数。有趣的是,0x8000的两个补码本身是0x8000(因为值+32768不适合有符号2字节整数的范围)。
那么这对你的功能意味着什么?一点一点,这具有切换符号位的效果,这里有一些例子:
f(0) = f(0x0000) = 0x8000 = -32768
f(1) = f(0x0001) = 0x8001 = -32767
f(0x8000) = 0
f(0x7fff) = 0xffff
似乎这可以表示为val ^= 0x8000
,但是当时可能还没有在Borland中实现XOR运算符?