|
-
Sep 27th, 2000, 05:16 AM
#1
Hi!
I'm working on some conversion stuff, and would like to know why this isn't working with negative values. The following 2 Functions are from microsoft themselves and are functional & tested (by me...):
Code:
Public Function HiByte(ByVal wParam As Integer) As Byte
HiByte = wParam \ &H100 And &HFF&
End Function
Public Function LoByte(ByVal wParam As Integer) As Byte
LoByte = wParam And &HFF&
End Function
So I tried to put them back together, but keep getting overflows with negative values...
Code:
Public Function Bytes2Word(ByVal bHiByte As Byte, ByVal bLoByte As Byte) As Integer
Bytes2Word = (bHiByte * &H100) Or (bLoByte And &HFF&)
End Function
Does anyone know jow to correctly do this? (Please test this/your code before replying)
-
Sep 27th, 2000, 05:30 AM
#2
Sorry, I don't know the answer , but Yonatan would know this.
-
Sep 27th, 2000, 05:57 AM
#3
Probably cos you're using unsigned bytes. The sign (pos or negative) takes an extra bit at the front of the byte. That would make the length of a signed byte equaling 255 be 9 bits long. I think.
This is something I haven't actually tested in VB - it's just based on general computing principles.
- gaffa
-
Sep 27th, 2000, 06:51 AM
#4
Guru
Yep Scorp, your answer was correct, 2 points. 
This could be done with bitwise comparison (as you are doing) but it is not as much fun as copying the memory directly.
Here's the best way (in my opinion):
Code:
Option Explicit
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDest As Any, pSrc As Any, ByVal cbSrc As Long)
Function LoByte(ByVal wWord As Integer) As Byte
Call CopyMemory(LoByte, wWord, 1)
End Function
Function HiByte(ByVal wWord As Integer) As Byte
Call CopyMemory(HiByte, ByVal VarPtr(wWord) + 1, 1)
End Function
Function MakeWord(ByVal btLoByte As Byte, ByVal btHiByte As Byte) As Integer
Call CopyMemory(MakeWord, btLoByte, 1)
Call CopyMemory(ByVal VarPtr(MakeWord) + 1, btHiByte, 1)
End Function
Enjoy! 
And, your overflows are because a Byte in VB is unsigned. It cannot receive negative values.
Code:
Dim MyByte As Byte
MyByte = -1 ' Overflow
-
Sep 27th, 2000, 09:09 AM
#5
But why won't this for negative values work then? I've tried this one, but to no avail... Help?
Code:
If bHiByte > &H80 Then
Byte2Word = -(((bHiByte - &H80) * &H100) Or (bLoByte And &HFF&))
Else
Byte2Word = (bHiByte * &H100) Or (bLoByte And &HFF&)
End If
-
Sep 27th, 2000, 01:51 PM
#6
Guru
Use my LoByte, HiByte and MakeWord functions.
Also, for negative numbers, use the LoByte function to unsign them.
For example:
Code:
' This will not work for negative values:
MyWord = MakeWord(MyLoByte, MyHiByte)
' This will work for any values:
MyWord = MakeWord(LoByte(MyLoByte), LoByte(MyHiByte))
It may seem like it does not matter (a byte is a byte) but it will actually make it possible to use negative values.
Enjoy!
-
Sep 27th, 2000, 02:48 PM
#7
Fanatic Member
This is stupid guys, he made an error by not considering the max. length of an integer/byte/long.
The erroneous function is Bytes2Word.
You're doing a multiplication with &h100 (=256). Since a byte can only be 255, an error occurs when sending i.e. &h88 as the first parameter.
You can't change the parameter to an integer because the multiplication could set b15 of the word, wchich also creates an error (integers are >=-32768 and <+32768).
So, just handle the parameters as a long (I used Clng) and no error will occur anymore!
Code:
Option Explicit
Private Sub Form_Paint()
Me.Cls
Me.Print "1024d = " & Format$(Hex(HiByte(1024)), "00"); Format$(Hex(LoByte(1024)), "00")
Me.Print Bytes2Word(&H88, 0)
End Sub
Public Function HiByte(ByVal wParam As Integer) As Byte
HiByte = wParam \ &H100 And &HFF&
End Function
Public Function LoByte(ByVal wParam As Integer) As Byte
LoByte = wParam And &HFF&
End Function
Public Function Bytes2Word(ByVal bHiByte As Byte, ByVal bLoByte As Byte) As Long
Bytes2Word = (CLng(bHiByte) * &H100) Or (CLng(bLoByte) And &HFF&)
End Function
-
Sep 27th, 2000, 07:26 PM
#8
I'm very sorry guys.... BUT:
1) Yonatan: I like your solution. It's very cretaive and functional. But I don't like the call the API for such a simple thing. It should be possible in "simple" (or "clean" or "normal" or whatever you like") VB.
2) Mad Compie: When I pass the vale -1234 to HiByte I get 252, and to LoByte I get 46. So passing 252 and 46 to Byte2Word it should return -1234 but instead it returns 64558. I also thought of that (using Cint where you are using Clng) but it doesn't work.
Is there NO way around this problem? I don't think I can accept that... Anyone? Let's put our heads together if we can't get it to work....
-
Sep 28th, 2000, 06:21 AM
#9
-
Sep 28th, 2000, 07:00 AM
#10
-
Sep 28th, 2000, 07:13 AM
#11
My function DOES return an Integer. I'm at this point now where I've got:
Code:
If bHiByte >= &H80 Then ' Negative value
Byte2Word = (((((bHiByte And &H7F) - 1) * &H100) Or bLoByte) Or &H8000)
' AND &H7F = Change Byte's Sign to Positive
' * &H100 = Shift 8 bits -> Left
' Or bLoByte = Add LowByte
' Or &H8000 = Change Sign back to negative.
Else ' Positive value
Byte2Word = (bHiByte * &H100) Or (bLoByte And &HFF&)
End If
But it won't work for the values -256 to 0 and some other (seemingly random but surely not random)... I'm still working on it... If anyone knows, please let me know too...
-
Sep 28th, 2000, 07:32 AM
#12
Guru
Here is a slow solution without CopyMemory:
Code:
Function LoByte(ByVal wWord As Integer) As Byte
LoByte = wWord And &HFF
End Function
Function HiByte(ByVal wWord As Integer) As Byte
HiByte = wWord \ &H100 And &HFF
End Function
Function MakeWord(ByVal btLoByte As Byte, ByVal btHiByte As Byte) As Integer
MakeWord = CInt("&H" & Hex(btLoByte Or (CLng(btHiByte) * &H100)))
End Function
To use MakeWord with any values, including negative:
Call MakeWord(LoByte(MyLoByte), LoByte(MyHiByte))
But, CopyMemory is still the fastest, and in my opinion, the best solution.
I'll get over it.
-
Sep 28th, 2000, 07:45 AM
#13
Yonatan: Have you tried your code? I'm very sorry but it doesn't work for me...
Paste this in a form and see what it does...
Code:
Option Explicit
Const MinInt = -32768
Const MaxInt = 32766
Function LoByte(ByVal wWord As Integer) As Byte
LoByte = wWord And &HFF
End Function
Function HiByte(ByVal wWord As Integer) As Byte
HiByte = wWord \ &H100 And &HFF
End Function
Function MakeWord(ByVal btLoByte As Byte, ByVal btHiByte As Byte) As Integer
MakeWord = CInt("&H" & Hex(btLoByte Or (CLng(btHiByte) * &H100)))
End Function
Private Sub Form_Load()
Dim T As Integer
Dim a As Byte
Dim b As Byte
For T = MinInt To MaxInt
a = HiByte(T)
b = LoByte(T)
If MakeWord(b, a) <> T Then Debug.Print T & "<>" & MakeWord(b, a)
'Also a,b doesn't work...
'If MakeWord(a, b) <> T Then Debug.Print T & "<>" & MakeWord(a, b)
Next T
End Sub
[Edited by RobIII on 09-28-2000 at 08:47 AM]
-
Sep 28th, 2000, 07:50 AM
#14
Maybe I'll go with the CopyMemory thing then.. That one DOES work.. But I still find it strange I (we?) can't get this thing to work correctly....
But what I've forgotten all the time is to thank you for all of your efforts (everybody!)
-
Sep 28th, 2000, 07:56 AM
#15
DAMN. Watch these timings:
CopyMemory loop (in sec):
0,3515625
0,3515625
0,359375
0,3515625
0,359375
0,359375
0,359375
"Normal/Clean/Simple VB" loop (in sec):
0,2890625
0,2890625
0,2773438
0,2890625
0,2929688
0,2890625
0,2890625
Number of iterations was the same in both tests. Although my function Didn't return the correct results...
So CopyMemory IS slower... I think I'll get back and try a bit more 'till my function functions....
-
Sep 28th, 2000, 07:59 AM
#16
Guru
So you really hate CopyMemory. 
Two mistakes in the "clean" VB code. 
Code:
Const MaxInt = 32767 ' Not: 32766
' And, as I said, pass the LoBytes of the values to make it work.
If MakeWord(LoByte(b), LoByte(a)) <> T Then Debug.Print T & "<>" & MakeWord(LoByte(b), LoByte(a))
-
Sep 28th, 2000, 08:25 AM
#17
Guru
I tested the timing and here is my conclusion.
It seems that, for simple LoByte and HiByte, the delay of loading the Kernel32.DLL, getting the address of RtlMoveMemory and calling it was too much. 
So for LoByte and HiByte, the pure VB version was a little bit faster.
But, for MakeWord, the CopyMemory solution is significantly faster (almost 3 times faster).
So here are the fastest functions I thought of:
Code:
Option Explicit
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDest As Any, pSrc As Any, ByVal cbSrc As Long)
Function LoByte(ByVal wWord As Integer) As Byte
LoByte = wWord And &HFF
End Function
Function HiByte(ByVal wWord As Integer) As Byte
HiByte = wWord \ &H100 And &HFF
End Function
Function MakeWord(ByVal btLoByte As Byte, ByVal btHiByte As Byte) As Integer
Call CopyMemory(MakeWord, btLoByte, 1)
Call CopyMemory(ByVal VarPtr(MakeWord) + 1, btHiByte, 1)
End Function
' Best usage for MakeWord:
MyWord = MakeWord(SomeValueForLoByte And &HFF, SomeValueForHiByte And &HFF)
' Using the "And &HFF" thing in place works best and fastest for negative values.
Enjoy!
-
Sep 28th, 2000, 08:48 AM
#18
Yeah! Now that's what I call productive thinking. I'm glad we "sorted it out". Thank you, very, very much
Rob.
-
Sep 28th, 2000, 01:12 PM
#19
Fanatic Member
When dealing with bits and bytes, you normally shouldn't pay attention to the leftmost signbit.
It's only interesting if we want to do some calculations with the values, otherwise, $FF is 255 and not -1. It's completely up to you if you want to use signed or unsigned values.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|