我需要用 Java 翻译这行代码,但我不确定如何处理 ptrdiff_t。不知道它在这里做什么。顺便说一下,mask_block 的类型是 size_t。
size_t lowest_bit = mask_block & (-(ptrdiff_t)mask_block);
谢谢
谨防!这有点神奇!
( x & ~(x-1) )
返回表达式中的最低设置位。由于整数的补码表示,原始代码的作者决定使用( x & (-x) )
实际上是相同的。但是(原作者认为)要让你需要使用有符号类型,并且如前所述,是有符号的,是无符号的。-x
ptrdiff_t
size_t
由于 Java 没有无符号类型,因此mask_block
将毫无问题地工作。int
mask_block & (-mask_block)
请注意,由于有符号和无符号类型之间的互操作性,强制转换在 C++ 中也是多余的。
ptrdiff_t
是应该用于两个指针之间的(整数)差异的类型。即,一个指针与另一个指针相减的结果。它是一个有符号整数,并且应该足够大以存储最大可能数组的大小(所以在 Java 中,这只是一个int
,我猜)
ptrdiff_t
是类型的名称,例如int
or ::std::string
。C++ 标准承诺这种类型将是一个足够大的整数类型,以容纳您可以减去的任何两个指针之间的差异。当然,减去指针的想法在 Java 中是一个相当陌生的概念。为了能够做到这一点,ptrdiff_t
必须能够容纳负数。
使用的子表达式ptrdiff_t
是转换表达式,如 Java 类型转换。然而,与 Java 类型转换不同的是,C++ 类型转换表达式更加危险和丑陋。它们可用于 Java 会拒绝的各种不同类型的转换。有时它们会产生令人惊讶的结果。
在这种情况下,看起来有人需要一个值,它是某种无符号整数(可能是一个unsigned long
或什么)才能为负数。他们需要把它变成一个有符号的值。ptrdiff_t
通常是平台支持的最大大小整数。因此,如果您要将任意无符号整数类型转换为有符号整数类型ptrdiff_t
,那么使用的类型最不可能通过 C++ 相当丑陋的强制转换操作导致某种奇怪的截断或符号更改。
特别是,看起来他们想要的类型是size_t
,这是 C++ 标准中的另一种类型。它是一个无符号类型(就像我猜测的那样),并且保证是一个整数类型,它大到足以容纳内存中任何可能对象的大小。它的大小通常与ptrdiff_t
.
编写代码的人想要这样做的原因是一个有趣的位操作技巧。为了向您展示诀窍,我将向您展示此表达式如何在多种场景中发挥作用。
假设mask_block
是 48。假设在这个假设的平台上,size_t
是 16 位(非常小,但这只是一个示例)。然后在二进制中,mask_block
看起来像这样:
0000 0000 0011 0000
并且-(ptrdiff_t)mask_block
是-48,看起来像这样:
1111 1111 1101 0000
那么,48 & -48
这是不是:
0000 0000 0001 0000
这是 16。请注意,这是 48 中最低设置位的值。让我们试试 50。50 看起来像这样:
0000 0000 0011 0010
-50 看起来像这样:
1111 1111 1100 1110
所以,50 & -50
看起来像这样:
0000 0000 0000 0010
这是 2。再次注意这是 50 中最低设置位的值。
所以这只是一个技巧来找到mask
. 变量被调用的事实lowest_bit
应该是一个线索。:-)
当然,这个技巧并不是完全可移植的。一些 C 和(现在可能是 C++)运行的平台不使用二进制补码表示,这个技巧在这些平台上不起作用。
在 Java 中,您可以这样做long lowest_bit = mask_block & -mask_block;
并获得相同的效果。Java 保证二进制补码整数,甚至没有无符号整数。所以它应该工作得很好。
x & -x
是一种清除所有位的技巧,x
不包括其最低位。
对于 的所有非零值x
,它是1 << lb
,其中lb
是最低有效位的位置(从 0 开始计数)。
为什么要投到ptrdiff_t
? 没有进一步的知识,很难说。我什至不确定是否需要演员阵容。ptrdiff_t
保证是有符号整数类型,并且size_t
始终是无符号整数类型。所以,我猜想 C++ 代码的作者想要确保它是有符号的并且具有与指针相同的大小。只需忽略强制转换,将代码移植到 Java 就足够了,因为在 Java 中,所有整数都是有符号的。
生成的代码也将比原始 C/C++ 版本更可移植,后者假定机器使用2 的补码来表示整数,尽管(至少在理论上)C 或 C++ 标准不能保证。但是,在 Java 中,保证 JVM 必须使用 2 的补码。