はじめまして。
VB 6.0を使用しています。
あるデータをバイナリで開き、ある2バイトのデータをINT型に変更しようと関数を作成したのですが、オーバーフローになることがあります。
関数は、以下の通りです。
Public Function ByteToInt(Low As Byte, Up As Byte) As Integer
ByteToInt = IIf(Up > &H7F, (Low + (CLng(Up) * &H100)) - &H10000, Low + (CLng(Up) * &H100))
End Function
処理的には、間違ってないような気がするのですが、よろしくお願いします。
> オーバーフローになることがあります。
具体的には、どんな値を渡したときですか?
以下の様にして試してみましたが・・・
エラーにはなりませんよ。
-----------------------------------------------
Dim i As Integer, j As Integer
For j = 0 To 255
For i = 0 To 255
Debug.Print i, j, ByteToInt(CByte(i), CByte(j))
Next
Next
-----------------------------------------------
他の部分が原因では?
ご返答ありがとうございます。
Low 12 UP 144が渡ると、オーバーフローします。
> Low 12 UP 144が渡ると、オーバーフローします。
当方ではオーバーフローしませんでしたが……。
他の部分が原因では?
Option Explicit
Private Sub Form_Load()
Const L As Byte = 12
Const U As Byte = 144
Dim result As Integer
result = ByteToInt(L, U)
Debug.Print Hex(result)
End Sub
'Private Function ByteToInt(ByVal Low As Byte, ByVal Up As Byte) As Integer
Public Function ByteToInt(Low As Byte, Up As Byte) As Integer
ByteToInt = IIf(Up > &H7F, (Low + (CLng(Up) * &H100)) - &H10000, Low + (CLng(Up) * &H100))
End Function
IIFをIF文に変更すると、なぜかうまく動きました。
ありがとうございました。
あともうひとう質問なのですが、
魔界の仮面弁士さんが記述していただいた
Option Explicit
Private Sub Form_Load()
Const L As Byte = 12
Const U As Byte = 144
Dim result As Integer
result = ByteToInt(L, U)
Debug.Print Hex(result)
End Sub
'Private Function ByteToInt(ByVal Low As Byte, ByVal Up As Byte) As Integer
Public Function ByteToInt(Low As Byte, Up As Byte) As Integer
ByteToInt = IIf(Up > &H7F, (Low + (CLng(Up) * &H100)) - &H10000, Low + (CLng(Up) * &H100))
End Function
を実行すると resultは-28860となり、"900C"をデバッグしますが、Windowsの関数電卓で16進"900C"を10進に直すと36876を返します。
36876のほうが正しいような気がするのですが…。
できれば36876を取得したいのですが…。
すいません、初歩的な質問で。
その手の変換関数では、ByVal 指定を付けるべきかと。
> resultは-28860となり、"900C"をデバッグしますが、
ん……? そんなハズは無いのですが。値を写し間違えていませんか?
> Windowsの関数電卓で16進"900C"を10進に直すと36876を返します。
Word(16bit 整数型)サイズで 16進数/10進数変換される場合、
符号付き整数型なら -28660、符号無しなら、36876 ですよね。
(関数電卓で、-28660 を16進数変換してみましょう)
符号付きの場合、最上位ビットを「0は正数、1は負数」として扱うので、
16bitサイズの整数型の場合、符号付きか符号無しかによって、
0000 〜 7FFF → 0 〜 32767
8000 〜 FFFF → -32768 〜 -1 または 32768 〜 65535
という値とみなされます。
今回の -28660 と 36876 の場合、両者はメモリ配置的には同じ値ですので、
それを API 等に渡す分には、どちらの値を使っても同じ結果を得られます。
> できれば36876を取得したいのですが…。
あなたの作成された関数では無理ですよ。戻り値が Integer 型ですから、
-32768〜32767 の範囲までしか返せません。
VB2005 なら、符号無し16bit整数型(UShort)もサポートしていますが、
VB6 にはそれがありませんしね。16bit整数型は符号付きのみです(Integer)。
一応、「Debug.Print &H900C%; &H900C&」の結果からもわかるように、
Long 型で扱うようにすれば、32768 以上の値も扱えます。
ただし型サイズが変化するので、API などに渡す場合には都合が悪くなります。
ご返答ありがとうございます。
>ん……? そんなハズは無いのですが。値を写し間違えていませんか
すいません。写し間違えです。
>あなたの作成された関数では無理ですよ。戻り値が Integer 型ですから、
>-32768〜32767 の範囲までしか返せません。
INT型の値範囲を忘れていました。すいません。
> できれば36876を取得したいのですが…。
この関数の帰り値を一度Hex関数で16進に直し、
&H900C&
といったように、Long型に直そうと思っているのですが可能でしょうか?
CLng("&H" & Hex(ByteToInt()) & "&")
と考えたのですが、無理でした。
関数そのものをlongのものに書き換え、うまくいきました。
いろいろありがとうございました。
ツイート | ![]() |