Easier way to convert big-endian to little-endian?

New to FreeBASIC? Post your questions here.
Mindless
Posts: 110
Joined: Jun 25, 2005 14:50
Location: USA

Easier way to convert big-endian to little-endian?

Postby Mindless » Jun 22, 2006 2:33

Code: Select all

size = ((size and &hff) shl 24) or ((size and &hff00) shl 8) or ((size and &hff0000) shr 8) or ((size and &hff000000) shr 24)

size is a uinteger which is being converted from big- to little-endian... is there a shorter/easier way to do this?
yetifoot
Posts: 1710
Joined: Sep 11, 2005 7:08
Location: England
Contact:

Postby yetifoot » Jun 22, 2006 3:18

You could do:

Code: Select all

ASM
  mov eax, dword ptr [size]
  bswap eax
  mov dword ptr [size], eax
End ASM


I'd guess its faster, but I haven't tested it. Otherwise I don't know a better way in actual BASIC code.
Mindless
Posts: 110
Joined: Jun 25, 2005 14:50
Location: USA

Postby Mindless » Jun 22, 2006 3:52

Awesome -- that's a lot simpler.
anonymous1337
Posts: 5494
Joined: Sep 12, 2005 20:06
Location: California

Postby anonymous1337 » Jun 22, 2006 4:12

ASM's a lot faster too:

Code: Select all

Dim size as uinteger
Dim x as integer
dim t as double

size = 24

t = timer

for x = 0 to 100000
   
    ASM
      mov eax, dword ptr [size]
      bswap eax
      mov dword ptr [size], eax
    End ASM
   
next

Print "ASM Time: " & timer - t

t = timer

for x = 0 to 100000

    size = ((size and &hff) shl 24) or ((size and &hff00) shl 8) or ((size and &hff0000) shr 8) or ((size and &hff000000) shr 24)
   
next

Print "Other: " & timer - t

sleep
1000101
Posts: 2556
Joined: Jun 13, 2005 23:14
Location: SK, Canada

Postby 1000101 » Jun 22, 2006 5:22

The asm version does lock you into x86 processors which limits your targets after the gcc port.

Also, presumably, you're doing endien swapping in not time-critical code. If it's happening in time-critial loops then one wonders what you are doing.
yetifoot
Posts: 1710
Joined: Sep 11, 2005 7:08
Location: England
Contact:

Postby yetifoot » Jun 22, 2006 5:32

Good points 1000101, also testing on my P4 the time difference was tiny, even on a long test, so i'd probably prefer to just stick to BASIC. You could make a macro or something, to avoid writing it over and over.
cha0s
Site Admin
Posts: 5317
Joined: May 27, 2005 6:42
Location: Illinois
Contact:

Postby cha0s » Jun 22, 2006 5:49

yeah, that's quite fast. I tried beating it using pointers, no go ;) too many assignments i guess.

edit: in case you're unfamiliar with macros:

Code: Select all

#Define fb_BSwap(size) _
  size = ( ( size And &hff ) Shl 24 ) Or ( ( size And &hff00 ) Shl 8 ) Or ( ( size And &hff0000 ) Shr 8 ) Or ( ( size And &hff000000 ) Shr 24 )


now you can just do

Code: Select all

fb_BSwap( myNumber )


it will then be flipped.
1000101
Posts: 2556
Joined: Jun 13, 2005 23:14
Location: SK, Canada

Postby 1000101 » Jun 22, 2006 12:47

These macros may be useful. One is the same as the one cha0s posted but the other two preform useful functions.

Code: Select all

'' Converts a msb dword to a lsb dword
#Define bo_conv_4(ID)                  ( ( ( ID And &HFF000000 ) Shr 24 ) Or _
                                         ( ( ID And &H00FF0000 ) Shr  8 ) Or _
                                         ( ( ID And &H0000FF00 ) Shl  8 ) Or _
                                         ( ( ID And &H000000FF ) Shl 24 ) )

'' Converts a msb word to a lsb word
#Define bo_conv_2(ID)                  ( ( ( ID And &HFF00 ) Shr 8 ) Or _
                                         ( ( ID And &H00FF ) Shl 8 ) )

'' Converts a 4-byte string to a uinteger
#Define FourCC(ID)                     ( ( Asc( ID, 1 )        ) Or _
                                         ( Asc( ID, 2 ) Shl  8 ) Or _
                                         ( Asc( ID, 3 ) Shl 16 ) Or _
                                         ( Asc( ID, 4 ) Shl 24 ) )


bo_conv_4 is a byte-order (endien) conversion of a dword (4 bytes) where as bo_conv_2 is a byte-order conversion of a word (2 bytes).

FourCC is a four-bye character code to uinteger macro.

All of these functions are used in some code of mine to real 68k Mac resource forks which have been bin-hexed on an x86 partition.
jevans4949
Posts: 1156
Joined: May 08, 2006 21:58
Location: Crewe, England

Postby jevans4949 » Jun 22, 2006 20:58

1000101 wrote:The asm version does lock you into x86 processors which limits your targets after the gcc port.

Actually, the whole big-endian - little-endian thing presents a portability problem for any intended cross-platform software or files.

Ultimately, I suppose the solution would have to be to have specific big-endian and little-endian integer types built into the compiler, which could then generate processor-specific code to deal with each type.

Most variables internal to the program would continue to be "don't care" format.

On the other hand, if Apple are swithcing to x86 processors, are the little-endians going to win sooner or later anyway?

P.S.: This is not a Whinge or a Change Request!
1000101
Posts: 2556
Joined: Jun 13, 2005 23:14
Location: SK, Canada

Postby 1000101 » Jun 22, 2006 21:47

jevans4949 wrote:Actually, the whole big-endian - little-endian thing presents a portability problem for any intended cross-platform software or files.
Well no kidding, which is the point of endian swapping. ie: convert it to the proper format for the machine you're running on. If you're on a 68k CPU you're not going to convers 68k data, however, if you're on a 68k CPU you need to convert x86 data to the proper endianness.


jevans4949 wrote:Ultimately, I suppose the solution would have to be to have specific big-endian and little-endian integer types built into the compiler, which could then generate processor-specific code to deal with each type.

Most variables internal to the program would continue to be "don't care" format.
erm, The last thing I want is to use 68k dwords on an x86 machine. It would be horribly slow. I'll stick to converting the endianness of the data to working with the CPU native endianness.


jevans4949 wrote:On the other hand, if Apple are swithcing to x86 processors, are the little-endians going to win sooner or later anyway?
Ok, but how does this affect old code and programs which will never be ported? You still need to be able to read old data if that's your goal.
arenth
Posts: 511
Joined: Aug 30, 2005 6:22

Postby arenth » Jun 22, 2006 22:11

Pure FBC version of bswap.

Code: Select all

function FB_BSWAP(byval sourceInt as integer) as integer
   dim tempInt as integer = sourceInt
   dim tempPTR as byte ptr = cptr(byte ptr, @tempInt)

   swap tempPTR[0], tempPTR[3]
   swap tempPTR[1], tempPTR[2]
   return tempInt
end function
   
   dim size as integer = 24
   size = fb_BSWAP(size)
   print size
   sleep


Since its in pure FB it should work on any platform FB works on.
cha0s
Site Admin
Posts: 5317
Joined: May 27, 2005 6:42
Location: Illinois
Contact:

Postby cha0s » Jun 23, 2006 0:00

hahah arenth, thats what i was saying i tried; it's quiote a bit slower, and SHL, SHR is "pure fb" too...

btw you dont even need a temp container, just swap byte [0], [3] and byte [1], [2]. but ANYWAYS shifting is faster! i posted so that no one else would take the time to do it >.>
jevans4949
Posts: 1156
Joined: May 08, 2006 21:58
Location: Crewe, England

Postby jevans4949 » Jun 23, 2006 0:35

1000101 wrote:
jevans4949 wrote:Ultimately, I suppose the solution would have to be to have specific big-endian and little-endian integer types built into the compiler, which could then generate processor-specific code to deal with each type.

Most variables internal to the program would continue to be "don't care" format.
erm, The last thing I want is to use 68k dwords on an x86 machine. It would be horribly slow. I'll stick to converting the endianness of the data to working with the CPU native endianness.

I think you miss my point. If you can specify to the compiler the endianness of a field on an external file, e.g., png or bmp, and the target machine for the compile, then the compiler can generate the bswap, or whatever the 68k equivalent might be, when needed.

Obviously, if you were referencing a field heavily and had the need for speed, then your program would copy the input field into a local variable in the native format, and copy the local field back to the output record immediately before re-writing. Just the same as if the number was in character format.

Of course, if there is no intention that a file will ever be ported from the system it's created on, then data fields can continue to be in native format.

The principle could be extended to other formats, e.g. EBCDIC character coding, other popular floating point formats, packed decimal formats ... I even encountered a mini-computer with a 6-byte integer format, with the lower 4 bytes big-endian followed by the upper 2 bytes big-endian!
arenth
Posts: 511
Joined: Aug 30, 2005 6:22

Postby arenth » Jun 23, 2006 7:58

I used a temp container, because I had originally done it without swap.


Code: Select all


function FB_BSWAP(byval sourceInt as integer) as integer
   dim tempInt as integer
   dim tempPTR as byte ptr = cptr(byte ptr, @tempInt)

   tempPTR[0] = (@sourceInt)[3]
   tempPTR[3] = (@sourceInt)[0]
   tempPTR[1] = (@sourceInt)[2]
   tempPTR[2] = (@sourceInt)[1]

   return tempInt
end function
   
   dim size as integer = 24
   size = fb_BSWAP(size)
   print size
   sleep
1000101
Posts: 2556
Joined: Jun 13, 2005 23:14
Location: SK, Canada

Postby 1000101 » Jun 23, 2006 17:16

jevans4949 wrote:I think you miss my point.


No, I got your point. Your idea would just results in incredibly slow executables or programming which would require a hack to get around the data format of the structs. Also, it's only a couple structs, generally, which would need this and would be simpler to just use a macro conversion after loading and before saving.

Return to “Beginners”

Who is online

Users browsing this forum: No registered users and 12 guests