从int减去0x8000

时间:2014-01-23 23:49:37

标签: c

我正在逆向工程一些旧的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,但是交换负数和正数(不改变顺序)。最终结果是所有数字具有相同的顺序(但不同的值),就好像它们首先是无符号的一样。

(...这不是本程序中最糟糕的代码示例)

2 个答案:

答案 0 :(得分:3)

在Borland C 3.x中,intshort是相同的:16位。 long是32位。

十六进制文字具有可以表示值的第一种类型:intunsigned intlong intunsigned long int

对于Borland C,0x8000是十进制值32768,不适合int,但会在unsigned int中。所以unsigned int就是。

声明v -= 0x8000 ;v = v - 0x8000 ;

相同

在右侧,intv被隐式转换为unsigned int,根据规则,执行算术运算,产生rvalunsigned 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运算符?