What's up with this?

Everything else that doesn't fall into one of the other PB categories.
User avatar
Joakim Christiansen
Addict
Addict
Posts: 2452
Joined: Wed Dec 22, 2004 4:12 pm
Location: Norway
Contact:

What's up with this?

Post by Joakim Christiansen »

I just have to wonder...
Why is it that "long = $hex_here" actually reverses the hex code?
The code below demonstrates this:

Code: Select all

Procedure.s memoryToHex(address,length) ;returns a string containing the hex representation of the memory area
  Protected result$, i
  For i=0 To length-1
    result$ + RSet(Hex(PeekB(address+i),#PB_Byte),2,"0")+" "
  Next
  ProcedureReturn result$
EndProcedure
Procedure hexToMemory(address,hex$) ;converts hex into data
  Protected i, pos, len
  hex$ = RemoveString(hex$," ")
  len = Len(hex$)
  For i=1 To len Step 2
    PokeB(address+pos,Val("$"+Mid(hex$,i,2)))
    pos+1
  Next
EndProcedure

long = $04030201
Debug memoryToHex(@long,4)

hexToMemory(@long,"04030201")
Debug memoryToHex(@long,4)
I like logic, hence I dislike humans but love computers.
User avatar
Demivec
Addict
Addict
Posts: 4283
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Re: What's up with this?

Post by Demivec »

Joakim Christiansen wrote:I just have to wonder...
Why is it that "long = $hex_here" actually reverses the hex code?
The short answer is that value of a number is stored differently in memory than the way it is written.


The long answer to your question is that you were putting/getting the values from memory in the wrong order.

This takes place due to Intel PC's using the Little Endian format to store integers in memory.

Code: Select all

The Little Endian order stores the bytes of an integer n memory 
with the lowest valued byte first.

The Long (= $01020304) is stored at address $3000 like this:

Address : Value
  $3000 :  $04
  $3001 :  $03
  $3002 :  $02
  $3003 :  $01
You'll also see this crop up frequently when using constants for RGB values also. RGB stands for the way it is in memory (i.e. it's stored as RR GG BB), but if you supply a constant to one of PureBasic's drawing commands or poke it into memory directly as a Long you have to order the bytes correctly for the translation (i.e. $00BBGGRR). :wink:


Here's a version that doesn't reverse the byte-order of integers stored using a Little-Endian ordering:

Code: Select all

Procedure.s memoryToHex(Address,length) ;returns a string containing the hex representation of the memory area
  Protected result$, i
  For i=length-1 To 0 Step -1
    result$ + RSet(Hex(PeekB(Address+i),#PB_Byte),2,"0")+" "
  Next
  ProcedureReturn result$
EndProcedure
Procedure hexToMemory(Address,hex$) ;converts hex into data
  Protected i, pos, len
  hex$ = RemoveString(hex$," ")
  len = Len(hex$)
  For i=len - 1 To 0 Step -2
    PokeB(Address+pos,Val("$"+Mid(hex$,i,2)))
    pos+1
  Next
EndProcedure

long = $04030201
Debug memoryToHex(@long,4)

hexToMemory(@long,"04030201")
Debug memoryToHex(@long,4)
@Edit: removed the term 'correct' and replaced it with a more accurate description involving the 'endian-ness' . :wink:
Last edited by Demivec on Sat Aug 01, 2009 4:32 pm, edited 1 time in total.
User avatar
Joakim Christiansen
Addict
Addict
Posts: 2452
Joined: Wed Dec 22, 2004 4:12 pm
Location: Norway
Contact:

Re: What's up with this?

Post by Joakim Christiansen »

Thanks for your explanation, I got little clue about Little-endian or Big-endian...
Demivec wrote:The long answer to your question is that you were putting/getting the values from memory in the wrong order.
...
Here's a corrected version:
Well, different methods for different needs. I just want to clarify that to anyone else who may read this topic. My functions are perfect for low level messaging where you have to set the values of each bytes (network protocols, etc). And your variation of it is when you wanna read and set the integer values correctly I guess, or simply yours are for Little-endian and mine for Big-endian, right?
http://en.wikipedia.org/wiki/Endianness#Big-endian
http://en.wikipedia.org/wiki/Endianness ... networking
:lol: this stuff can probably be very confusing at times.

So... this would actually be more "correct"? :P

Code: Select all

Enumeration
  #littleEndian
  #bigEndian
EndEnumeration

Procedure.s memoryToHex(address,length,byteorder=#bigEndian)
  Protected result$, i
  If byteorder = #bigEndian
    For i=0 To length-1
      result$ + RSet(Hex(PeekB(address+i),#PB_Byte),2,"0")+" "
    Next
  ElseIf byteorder = #littleEndian
    For i=length-1 To 0 Step -1
      result$ + RSet(Hex(PeekB(Address+i),#PB_Byte),2,"0")+" "
    Next
  EndIf
  ProcedureReturn result$
EndProcedure
Procedure hexToMemory(address,hex$,byteorder=#bigEndian)
  Protected i, pos, len
  hex$ = RemoveString(hex$," ")
  len = Len(hex$)
  If byteorder = #bigEndian
    For i=1 To len Step 2
      PokeB(address+pos,Val("$"+Mid(hex$,i,2)))
      pos+1
    Next
  ElseIf byteorder = #littleEndian
    For i=len - 1 To 0 Step -2
      PokeB(Address+pos,Val("$"+Mid(hex$,i,2)))
      pos+1
    Next
  EndIf
EndProcedure

long = $04030201
Debug memoryToHex(@long,4,#littleEndian)

hexToMemory(@long,"04030201",#littleEndian)
Debug memoryToHex(@long,4,#littleEndian)
I like logic, hence I dislike humans but love computers.
User avatar
Demivec
Addict
Addict
Posts: 4283
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Re: What's up with this?

Post by Demivec »

Joakim Christiansen wrote:Thanks for your explanation, I got little clue about Little-endian or Big-endian...
Demivec wrote:The long answer to your question is that you were putting/getting the values from memory in the wrong order.
...
Here's a corrected version:
Well, different methods for different needs. I just want to clarify that to anyone else who may read this topic. My functions are perfect for low level messaging where you have to set the values of each bytes (network protocols, etc). And your variation of it is when you wanna read and set the integer values correctly I guess, or simply yours are for Little-endian and mine for Big-endian, right?
http://en.wikipedia.org/wiki/Endianness#Big-endian
http://en.wikipedia.org/wiki/Endianness ... networking
:lol: this stuff can probably be very confusing at times.

So... this would actually be more "correct"? :P
You are correct, I had used an inaccurate description. Your code was correct as it was, its effect was that it reversed the order of the bytes on a system that used little-endian ordering. :P

I have revised the wording in my former post to reflect this and to reduce any confusion that might result from someone scanning this thread.

Your code is an improvement by making both orderings usable.
User avatar
Joakim Christiansen
Addict
Addict
Posts: 2452
Joined: Wed Dec 22, 2004 4:12 pm
Location: Norway
Contact:

Post by Joakim Christiansen »

Good we agree :D

Btw, thanks to you I just updated my older post with commands for working with hex to support little-endian too:
viewtopic.php?p=284223
Based on this discussion I guess that the default byte order for longToHex() should be little-endian, but whatever; people may now choose whatever they prefer if they use my commands.
longToHex(long,byteorder)
I like logic, hence I dislike humans but love computers.
Post Reply