このコード行をJavaで翻訳する必要がありますが、ptrdiff_tについてどうしたらよいかわかりません。ここで何をするのかわからない。ちなみに、mask_blockのタイプはsize_tです。
size_t lowest_bit = mask_block & (-(ptrdiff_t)mask_block);
ありがとう
注意してください!これはちょっとした魔法です!
( x & ~(x-1) )
式で設定された最下位ビットを返します。元のコードの作成者は、整数の2 の補数( x & (-x) )
表現のために事実上同じである whichを使用することにしました。しかし (元の作者はそう考えていました)署名済みの型を使用する必要があり、以前に指摘したように、署名済みであり、署名されていません。-x
ptrdiff_t
size_t
Java には署名されていない型がないためmask_block
、問題なく動作int
しmask_block & (-mask_block)
ます。
符号付き型と符号なし型の間の相互運用性により、キャストは C++ でも不要であることに注意してください。
ptrdiff_t
2つのポインタ間の(整数)差に使用する必要があるタイプです。つまり、あるポインタを別のポインタから減算した結果です。これは符号付き整数であり、可能な最大の配列のサイズをストローするのに十分な大きさである必要があります(つまり、Javaでは、それは単純にint
、私は推測します)
ptrdiff_t
int
やのような型の名前です::std::string
。C++ 標準では、この型は、減算できる任意の 2 つのポインターの差を保持するのに十分な大きさの整数型になることが約束されています。もちろん、ポインターを差し引くという考え方は、Java ではかなり異質な概念です。これを行うには、ptrdiff_t
負の数を保持できる必要があります。
が使用されている部分式ptrdiff_t
は、Java 型キャストのようなキャスト式です。ただし、Java 型キャストとは異なり、C++ キャスト式はより危険で醜いものです。これらは、Java が躊躇するあらゆる種類の異なる型変換に使用できます。そして時には驚くべき結果をもたらすこともあります。
この場合、誰かunsigned long
が負になることができる何らかの種類の符号なし整数 (おそらく an または何か) である値を必要としていたようです。彼らはそれを符号付きの値に変換する必要がありました。ptrdiff_t
通常、プラットフォームがサポートする最大サイズの整数です。したがって、任意の符号なし整数型を符号付き整数型に変換するptrdiff_t
場合は、C++ のかなり醜いキャスト操作で何らかの奇妙な切り捨てや符号変更が発生する可能性が最も低い型を使用することになります。
特に、彼らが望んでいたsize_t
のは、C++ 標準の別の型である だったようです。これは(私が推測していたように) 符号なしの型であり、メモリ内の可能なオブジェクトのサイズを保持するのに十分な大きさの整数型であることが保証されています。通常は と同じサイズptrdiff_t
です。
コードを書いた人がこれをやりたいと思った理由は、興味深いビット操作のトリックでした。トリックを示すために、この式がさまざまなシナリオでどのように機能するかを示します。
48と仮定mask_block
します。この仮想プラットフォームでsize_t
は 16 ビットとしましょう (これは非常に小さいですが、これは単なる例です)。バイナリでは、mask_block
次のようになります。
0000 0000 0011 0000
は -48 で、-(ptrdiff_t)mask_block
次のようになります。
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++) が実行される一部のプラットフォームでは、2 の補数表現が使用されないため、このトリックはそれらのプラットフォームでは機能しません。
Java では、これを行うだけlong lowest_bit = mask_block & -mask_block;
で同じ効果が得られます。Java は 2 の補数の整数を保証し、符号なし整数すらありません。したがって、問題なく動作するはずです。
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 の補数を使用する必要があることが保証されています。