如何获取UInt64的值,toString唯一的方法?

时间:2014-06-22 10:38:04

标签: javascript firefox-addon jsctypes

我有这个: "ctypes.UInt64("7")"

由此返回:

var chars = SendMessage(hToolbar, TB_GETBUTTONTEXTW, local_tbb.idCommand, ctypes.voidptr_t(0));

所以

console.log('chars=', chars, chars.toString(), uneval(chars));

给出

'chars=' 'UInt64 {  }' "7" 'ctypes.UInt64("7")'

所以我可以通过chars.toString()来获取价值,但是我必须在其上运行parseInt,无论如何都要像财产那样阅读它?喜欢chars.UInt64

1 个答案:

答案 0 :(得分:4)

js-ctypes中64位整数的问题是Javascript缺少兼容类型。所有Javascript编号都是IEEE双精度浮点数(double),它们可以代表53-bit integers at most。因此,您甚至不应该尝试自己解析int,除非您知道结果适合double的事实。例如。你无法知道这一点。

E.g。请考虑以下事项:

// 6 * 8-bit = 48 bit; 48 < 53, so this is OK
((parseInt("0xffffffffffff", 16) + 2) == parseInt("0xffffffffffff", 16)) == false
// However, 7 * 8-bit = 56 bit; 56 < 53, so this is not OK
((parseInt("0xffffffffffffff", 16) + 2) == parseInt("0xffffffffffffff", 16)) == true
// Oops, that compared equal, because a double precision floating point
// cannot actual hold the parseInt result, which is still well below 64-bit!

让我们正确处理JS中的64位整数......

如果您只想进行比较,请使用UInt64.compare() / Int64.compare(),例如

// number == another number
ctypes.UInt64.compare(ctypes.UInt64("7"), ctypes.UInt64("7")) == 0
// number != another number
ctypes.UInt64.compare(ctypes.UInt64("7"), ctypes.UInt64("6")) != 0
// number > another number
ctypes.UInt64.compare(ctypes.UInt64("7"), ctypes.UInt64("6")) > 0
// number < another number
ctypes.UInt64.compare(ctypes.UInt64("7"), ctypes.UInt64("8")) < 0

如果您需要结果,但不确定它是否为32位无符号整数,则可以检测是否正在处理刚刚打包到Uint64的32位无符号整数:

ctypes.UInt64.compare(ctypes.UInt64("7"), ctypes.UInt64("0xffffffff")) < 0

Int64中32位有符号整数的模拟,但需要比较最小值和最大值:

ctypes.Int64.compare(ctypes.Int64("7"), ctypes.Int64("2147483647")) < 0 &&
ctypes.Int64.compare(ctypes.Int64("7"), ctypes.Int64("-2147483648")) > 0

因此,一旦您知道或检测到某些内容适合JS double,就可以安全地在其上调用parseInt

var number = ...;
if (ctypes.UInt64.compare(number, ctypes.UInt64("0xffffffff")) > 0) {
  throw Error("Whoops, unexpectedly large value that our code would not handle correctly");
}
chars = parseInt(chars.toString(), 10); 

(为了完整起见,还有UInt64.hi() / Int64.hi()UInt64.lo() / Int64.lo()来获得真正64位的高32位和低位整数和自己做64位整数数学(e.g.),但要小心结束。)

PS:SendMessage的返回值为intptr_t而不是uintptr_t,这在此非常重要,因为SendMessage(hwnd, TB_GETBUTTONTEXT, ...)可能会在失败时返回-1

所以把所有这些放在一起(未经测试):

var SendMessage = user32.declare(
    'SendMessageW',
    ctypes.winapi_abi,
    ctypes.intptr_t,
    ctypes.voidptr_t, // HWND
    ctypes.uint32_t, // MSG
    ctypes.uintptr_t, // WPARAM
    ctypes.intptr_t // LPARAM
);
// ...

var chars = SendMessage(hToolbar, TB_GETBUTTONTEXTW, local_tbb.idCommand, ctypes.voidptr_t(0));
if (ctypes.Int64.compare(chars, ctypes.Int64("0")) < 0) {
  throw new Error("TB_GETBUTTONTEXT returned a failure (negative value)");
}
if (ctypes.Int64.comare(chars, ctypes.Int64("32768")) > 0) {
  throw new Error("TB_GETBUTTONTEXT returned unreasonably large number > 32KiB");
}
chars = parseInt(chars.toString());