たびたびお世話になっています。yTakeといいます。
問題自体は解決しましたが、少々解説頂ければ幸いに存知ます。
バイナリーデータのビット操作(シフト)後のAND処理についてです。
元々、LongWordとすべきところをLongIntとしていた為、レンジエラーが生じていた物です。4バイト整数データを取り出すのに1バイト毎に読み出し、8ビットずつシフトさせた後、加算して数値化しています。
===引用抜粋===
var
c0, c1, c2, c3, Sx : LongWord;
buf : PAnsiChar;
c0 := Integer( buff[ M ]) and $000000FF;
c1 := ( Integer( buff[ M + 1 ]) shl 8 ) and $0000FF00;
c2 := ( Integer( buff[ M + 2 ]) shl 16 ) and $00FF0000;
c3 := ( Integer( buff[ M + 3 ]) shl 24 ) and $FF000000;
Sx := C0 + C1 + C2 + C3;
Matrix[ i ][ k ] := Sx;
M := M + 4;
===引用抜粋===
元々、LongIntとして定義して時はANDを取っていなかったのですが、その時はたまたま、読み取る4バイトデータが最上位ビットを使用しない値だったので、レンジエラーは生じていませんでした。(”c3 := ”の行でレンジエラー)
4バイトデータに"2147483648"以上のデータを含む場合にレンジエラーとなり判明した次第です。
ここで、LongIntをLongWordに定義し直す事で済むと思いましたが、
最上位バイトのデータをシフト後、ANDを取っておかないとやはりレンジエラーとなっています。
シフト後のANDはシフト時のビットゴミを0でマスクする程度に思っていましたので、必ずしもANDを取らなくても、レンジエラーとまではならない様に思えますが、なぜ、レンジエラーになるのでしょうか?
変数型をWordとする事で最上位ビットは数値データとみなされていて、Integerの場合では符号ビットとみなされてしまう為、レンジエラーとなっていたと考えます。
長々となってしまいましたが、解釈に苦慮しています。
ご教授頂ければと思います。
年末年始はさすがに回答者が少ないようですね
実行環境が無いので試していませんが
c3 := ( Integer( buff[ M + 3 ]) shl 24 );
と
c3 := ( Integer( buff[ M + 3 ]) shl 24 ) and $FF000000;
では、計算方法が異なります。
上記では式の中で使われている変数でもっとも大きいのが
「Integer型」ですのでIntegerとして計算されます。
その結果、値が2147483648になった瞬間エラーになります
下記では式の中で使われている変数でもっとも大きいのが
「LongWord型」ですのでLongWordとして計算されるのでエラーが出ません。
LongWord型はありませんが「$FF000000」という値を使った瞬間
LongWord型が使われていると解釈されますので
エラーが出ないのです。
and $FF000000の代わりに or $FFFFFFFF でもエラーが出なくなると思います
ン
まず、ノとフラでは表せる値の範囲が違います。
ヲサノコヲサュイアエキエクウカエクョョイアエキエクウカエキ
ヲサフラコヲサーョョエイケエケカキイケオヲサ
トでは数値型の範囲は厳密にチェックされます。
たとえウイで表せるとしても、負の値をフラ型の変数に代入するのは違反です。
ルールィアゥコヲサシフト演算ヲサヲサヲサヲサの結果はと同じ型になる
これにより
ヲサノィ」、クーゥヲサヲサイエ
の結果はノ型の負数ィュイアエキエクウカエクゥとなり、そのままフラ型の変数に代入しようとすれば範囲エラーになります。
さて、、ニニーーーーーーヲサとのを取った場合には、さらに二つのルールが関係します。
ィイゥヲサ定数式の型は、その定数を表せる中で最も範囲の狭い型になる
ィウゥヲサ整数型同士の演算の結果は、両辺がとり得るすべての値を含む最も小さな範囲の型になる
ルールィイゥにより、、ニニーーーーーーの型は符号なしウイ(フラ相当)になります。
そしてルールィウゥによって、ノとフラ両方の範囲を包含するノカエが結果となります。
ヲサノィュイアエキエクウカエクゥヲサヲサフラィ、ニニーーーーーーゥヲサスヲサノカエィ、クーーーーーーーゥ
結果はフラで表せる範囲に収まっているので、これを代入しても範囲エラーになりません。
で、ビット演算が目的であれば、最初から符号付きィノゥではなく符号なしィフラゥにキャストすれば
こういう面倒なことは起こらないのではないでしょうか。
スススススススススススススススススススススススススススススススススススススススス
ニコ ヤ
トコ イーアオッーアッーオィ月ゥ アキコウウコーケ 書込者ノト:ロ 「「 ン
モコ
さん、さん
ありがとうございました。
環境は、ラ7ィウイゥ+トナフミネノヲサリナウ でした。
トナフミネノでは整数型は厳密にチェックされると言う事で、以後気を付けたいと思います。
ただ、例えば、ノ型の変数へ「イアエキエクウカエク「を代入したり、フラ型の変数に「ュイアエキエクウカエク「を代入しようとすると、エラーになる分けですが、プログラム的にはいずれも単に「、クーーーーーーー「として与えられるだけですが、その変数型との不一致によってエラーになる分けですね。
蛇足ですが、とすると、エラーメッセージが適当ではない様に思えます。
変数型が違う旨のエラーメッセージの方が適当ではないでしょうかね。
実際、その様なエラーメッセージがありますし。
レンジチェックエラーだと、何か配列の要素の範囲外をアクセスした様な印象です。
ご解説頂き大変ありがとうございました。
スススススススススススススススススススススススススススススススススススススススス
ニコ
トコ イーアオッーアッーオィ月ゥ アクコウイコウキ 書込者ノト:ロ 」 ァ」ハノ
ン
では蛇足ついでに。「レンジチェックエラー」になるのは、トにおける整数型が、配列の添字と同じ「部分範囲型」のサブセットだからです。
部分範囲型というのは、「ここからここまでの値をとる順序型」と定義された型です。
例えば次の文は、アからアイまでの値をとる部分範囲型を定義しています。
ヲサヲサヤヘヲサスヲサアョョアイサ
この範囲外の数値をヤヘ型の変数に代入しようとしたら、範囲エラーになります。
ヲサヲサコヲサヤヘサ
ヲサョョョ
ヲサヲサコスヲサアサヲサッッヲサマヒ
ヲサヲサコスヲサアイサヲサッッヲサマヒ
ヲサョョョ
ヲサヲサコスヲサーサヲサッッヲサ範囲エラー。
ヲサヲサコスヲサアウサヲサッッヲサ範囲エラー。
この場合のエラーメッセージとして「レンジチェックエラー」というのは至極妥当ですよね?
「変数型が違う」だとおかしなことになります(アとかアイとかを代入するのも、ヤヘヲサコスヲサノヲサで型が違うから駄目じゃん。ヲサとなってしまいます)。
整数型も同じように、
ヲサヲサ
ヲサヲサヲサヲサノヲサスヲサュイアエキエクウカエクョョイアエキエクウカエキサ
ヲサヲサヲサヲサフラヲサスヲサーョョエイケエケカキイケオサ
といった部分範囲型として定義されています(少なくとも、そう定義されているように扱われます)。
そして、配列の要素の添字も「部分範囲型」で定義されます。
ヲサヲサ
ヲサヲサヲサヲサコヲサローョョカンヲサヲサモサヲサッッヲサこの「ーョョカ」は部分範囲型
だからどちらの場合も、範囲を超えていたら同じ「レンジチェックエラー」になるわけです。
スススススススススススススススススススススススススススススススススススススススス
ニコ yヤ
トコ イーアオッーアッーカィ火ゥ ーケコオイコエイ 書込者ノト:ロ 「「 ン
さん
大変ありがとうございます。
なるほど、変数型の定義内容まで思い至りませんでした。
”配列の要素の添字も「部分範囲型」で定義”と言うところで分かった気がします。
ちなみに、
ウヲサヲサコスヲサヲサィヲサノィヲサロヲサヘヲサォヲサウヲサンゥヲサヲサイエヲサゥサ
を
ウヲサヲサコスヲサヲサィヲサフラィヲサロヲサヘヲサォヲサウヲサンゥヲサヲサイエヲサゥサ
としたら、
「、ニーーーーーー「で「「を取らなくてもマヒでした。(「「は念の為、取りますが)
ありがとうございました。
ツイート | ![]() |