Ways of reversing the byte order of an unsigned integer

Place to talk about all that new hardware and decaying software you have.

Moderator: General Mods

lordmissus
Ignorant Child
Posts: 326
Joined: Mon Apr 06, 2009 10:10 pm
Location: 1984

Ways of reversing the byte order of an unsigned integer

Post by lordmissus »

I do things like this on byuu's board every now and then; asking people to post their own code for a particular thing. The task is normally simple, although the code can be as strange and esoteric as you like.

So, post your code to do the above, in the language of your choosing. Here is mine, in C#, that reverses the byte order of a ushort, uint or ulong,

Code: Select all

        static object swapEndian_g(object t) // reverse the byte order of a generic type (can be byte, ushort, uint or ulong)
        {
            int[] sizes = new int[] 
            { 
                sizeof(ushort), 
                sizeof(uint), 
                sizeof(ulong), 
                0x00
            };
            object[] types = new object[] 
            { 
                new ushort(), 
                new uint(), 
                new ulong() 
            };
            for(int i = 0; !types[sizes[sizes.Length - 1] = i++].GetType().IsInstanceOfType(t);)
            {
                if (i >= types.Length)
                {
                    throw new Exception("swapEndian_g(object t) ERROR! UNKNOWN TYPE ''''" + t.GetType() + "''''. Stop");
                }
            }
            ulong input = Convert.ToUInt64(t), ret = 0;
            for (int i = 0; i < sizes[sizes[sizes.Length - 1]]; i++)
            {
                ret |= ((input >> ((i ^ (sizes[sizes[sizes.Length - 1]] - 1)) << 3)) & 0xff) << (i << 3);
            }
            return Convert.ChangeType(ret, t.GetType());
        }
usage:
ushort x = (ushort)swapEndian_g((ushort)variable);
uint x = (uint)swapEndian_g((uint)variable);
ulong x = (ulong)swapEndian_g((ulong)variable);
SquareHead
Veteran
Posts: 970
Joined: Fri Jan 21, 2005 11:15 am
Location: Montana, United States

Re: Ways of reversing the byte order of an unsigned integer

Post by SquareHead »

Not quite sure I understood this correctly, but it made me think of a savestate editing program I wrote a long ass time ago (10 years), for FF3 for the famicom. Scary they still host a couple of my programs and their source over at Zophar's. I remember having to convert between how the famicom and the pc stored byte order. I was 20 at the time and did this in basic if you would believe this.

Code: Select all

INPUT "New exp max=9999999 "; exper
exper$ = HEX$(exper)
newexp$ = MID$(exper$, 1, 2)
newexp2$ = MID$(exper$, 3, 2)
newexp3$ = MID$(exper$, 5, 2)
IF newxp$ = "" THEN newxp$ = "00"
IF newxp2$ = "" THEN newxp2$ = "00"
IF newxp3$ = "" THEN newxp3$ = "00"
IF chartmp = 1 THEN char1xp1 = CHR$(VAL("&H" + newexp3$))
IF chartmp = 1 THEN char1xp2 = CHR$(VAL("&H" + newexp2$))
IF chartmp = 1 THEN char1xp3 = CHR$(VAL("&H" + newexp$))
IF chartmp = 2 THEN char2xp1 = CHR$(VAL("&H" + newexp3$))
IF chartmp = 2 THEN char2xp2 = CHR$(VAL("&H" + newexp2$))
IF chartmp = 2 THEN char2xp3 = CHR$(VAL("&H" + newexp$))
IF chartmp = 3 THEN char3xp1 = CHR$(VAL("&H" + newexp3$))
IF chartmp = 3 THEN char3xp2 = CHR$(VAL("&H" + newexp2$))
IF chartmp = 3 THEN char3xp3 = CHR$(VAL("&H" + newexp$))
IF chartmp = 4 THEN char4xp1 = CHR$(VAL("&H" + newexp3$))
IF chartmp = 4 THEN char4xp2 = CHR$(VAL("&H" + newexp2$))
IF chartmp = 4 THEN char4xp3 = CHR$(VAL("&H" + newexp$))
creaothceann
Seen it all
Posts: 2302
Joined: Mon Jan 03, 2005 5:04 pm
Location: Germany
Contact:

Re: Ways of reversing the byte order of an unsigned integer

Post by creaothceann »

SquareHead wrote:I remember having to convert between how the famicom and the pc stored byte order
They're the same (little endian). Maybe you mean human vs. logical display order...
vSNES | Delphi 10 BPLs
bsnes launcher with recent files list
lordmissus
Ignorant Child
Posts: 326
Joined: Mon Apr 06, 2009 10:10 pm
Location: 1984

Re: Ways of reversing the byte order of an unsigned integer

Post by lordmissus »

See the following. This is a new post I made on the one I put on byuu's board (I have several different methods of doing it, which is why there is so much code in this post; I can use a certain method depending on my mood.):
lordmister wrote:
gladius wrote:Oh my. That is an ... interesting piece of C# :). There is beauty (and speed) in simplicity.

Code: Select all

        static ushort Reverse(ushort input)
        {
            return (ushort)((input << 8) | (input >> 8));
        }
        static uint Reverse(uint input)
        {
            return (input << 24) | ((input << 8) & 0xFF0000) | ((input >> 8) & 0xFF00) | (input >> 24);
        }
        static void Main(string[] args)
        {
            Console.WriteLine(Reverse(0x1234).ToString("X"));
            Console.WriteLine(Reverse(0x12345678).ToString("X"));
        }

Yes well I wanted just oen generic function for all the types I need for this. Anyway I have separate functions fro each type aswell. See the following, which has the function I posted before, and new ones fro each specific type, in addition to some code for just testing everything to see if it works (look in Main()):

Code: Select all

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static int awesome(object t) // take a ushort, uint or ulong passed as an object, 
                                     // and return the size in bytes of the type actually passed
        {
            int[] sizes = new int[] // sizes that can be returned
            { 
                sizeof(ushort), 
                sizeof(uint), 
                sizeof(ulong), 
                0x00
            };
            object[] types = new object[]  // supported types are:
            { 
                new ushort(), 
                new uint(), 
                new ulong() 
            };
            for (int i = 0; !types[sizes[sizes.Length - 1] = i++].GetType().IsInstanceOfType(t); ) // determine the type
            {
                if (i >= types.Length) // if this is the case, an unsupported type was passed
                {
                    throw new Exception("awesome(object t) ERROR! UNSUPPORTED TYPE ''''" + t.GetType() + "''''. Stop");
                }
            }
            return sizes[sizes[sizes.Length - 1]]; // return the byte size of the type of object that was passed
        }

        static object swapEndian_g(object t) // reverse the byte order of a generic type (can be ushort, uint or ulong)
        {                                    // Using this is slow, but it supports all the types you need, and it's use of awesome features in C# is awesome
            int size = awesome(t);
            ulong input = Convert.ToUInt64(t), ret = 0;
            for (int i = 0; i < size; i++)
            {
                ret |= ((input >> ((i ^ (size - 1)) << 3)) & 0xff) << (i << 3);
            }
            return Convert.ChangeType(ret, t.GetType());
        }

        static string chex(object t) // Convert a ushort, uint or ulong to a string representing it in hex
        {
            int size = awesome(t); // get the size of the type of object passed
            string r = ""; // return string
            ulong x = Convert.ToUInt64(t); // make t more meaningful
            string hex = "0123456789ABCDEF"; // hex chars used for the conversion

            for(int i = 0; i < size; i++) // go through all bytes in the value passed, convert them to hex strings
            {
                r = (hex[(int)((x >> 4) & 0xf)] + "") + (hex[(int)(x & 0xf)] + "") + r;
                x >>= 8; // make way for the next byte
            }

            return r;
        }

        static ushort swapEndian(ushort x) // reverse the byte order of a ushort
        {
            ushort r = 0;
            for (int i = 0; i < sizeof(ushort); i++)
            {
                r |= (ushort)(((x >> ((i ^ (sizeof(ushort) - 1)) << 3)) & 0xff) << (i << 3));
            }
            return r;
        }

        static uint swapEndian(uint x) // reverse the byte order of a uint
        {
            uint r = 0;
            for (int i = 0; i < sizeof(uint); i++)
            {
                r |= (uint)(((x >> ((i ^ (sizeof(uint) - 1)) << 3)) & 0xff) << (i << 3));
            }
            return r;
        }

        static ulong swapEndian(ulong x) // reverse the byte order of a ulong
        {
            ulong r = 0;
            for (int i = 0; i < sizeof(ulong); i++)
            {
                r |= (ulong)(((x >> ((i ^ (sizeof(ulong) - 1)) << 3)) & 0xff) << (i << 3));
            }
            return r;
        }

        static void Main(string[] args)
        {
            // Testing the generic one
            object[] t = new object[] { (ushort)0xFFAA, (uint)0xFFA23BC4, (ulong)0xFFFFFFFFFFA23BC4 };
            for (int i = 0; i < t.Length; i++)
                Console.Write("{0}\n", chex(swapEndian_g(t[i])));
            Console.Write("\n\n");

            // Testing the separate functions that use explicit types
            Console.Write("{0}\n", chex(swapEndian((ushort)0xFFAA)));
            Console.Write("{0}\n", chex(swapEndian((uint)0xFFA23BC4)));
            Console.Write("{0}\n", chex(swapEndian((ulong)0xFFFFFFFFFFA23BC4)));

            Console.ReadKey(true);
        }
    }
}


You will notice that my swapEndian_g() function is smaller than before, because the code for determining the byte size of the object passed is now in a separate int function (awesome()) that is also used by the chex() function in my code.

In main() there is code to test both methods (reversing values from all three types using the generic function, and the same but using the three separate functions for each type). When running this program, I get the following output:

Code: Select all

AAFF
C43BA2FF
C43BA2FFFFFFFFFF


AAFF
C43BA2FF
C43BA2FFFFFFFFFF
Which is correct.
C# is explicit about byte sizes of various types, except for IntPtr that represents the natural word size on a given machine and is non-CLS compliant. However, despite the explicitly defined sizes in the specification itself, it's not impossible to create a non-conforming implementation, hence my use of sizeof. Using sizeof also makes you cool.

Also, explain to me what you mean by "interesting" :P
(the second, larger code sample is mine, the smaller one belongs to "gladius". The peice of code that he said was "interesting" is the same peice of code I posted here in this zboard thread in the first original post)
lordmissus
Ignorant Child
Posts: 326
Joined: Mon Apr 06, 2009 10:10 pm
Location: 1984

Re: Ways of reversing the byte order of an unsigned integer

Post by lordmissus »

I re-added byte support, since a convert-to-hex function is useless if it supports all the other types, but not byte. See:

Code: Select all

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static int awesome(object t) // take a ushort, uint or ulong passed as an object, 
                                     // and return the size in bytes of the type actually passed
        {
            int[] sizes = new int[] // sizes that can be returned
            { 
                sizeof(byte),
                sizeof(ushort), 
                sizeof(uint), 
                sizeof(ulong), 
                0x00        // this is used for the return value of the actual byte size
            };
            object[] types = new object[]  // supported types are:
            { 
                new byte(),
                new ushort(), 
                new uint(), 
                new ulong() 
            };
            for (int i = 0; !types[sizes[sizes.Length - 1] = i++].GetType().IsInstanceOfType(t); ) // determine the type
            {
                if (i >= types.Length) // if this is the case, an unsupported type was passed
                {
                    throw new Exception("awesome(object t) ERROR! UNSUPPORTED TYPE ''''" + t.GetType() + "''''. Stop");
                }
            }
            return sizes[sizes[sizes.Length - 1]]; // return the byte size of the type of object that was passed
        }

        static object swapEndian_g(object t) // reverse the byte order of a generic type (can be ushort, uint or ulong)
        {                                    // Using this is slow, but it supports all the types you need, and it's use of awesome features in C# is awesome
            int size = awesome(t);
            ulong input = Convert.ToUInt64(t), ret = 0;
            for (int i = 0; i < size; i++)
            {
                ret |= ((input >> ((i ^ (size - 1)) << 3)) & 0xff) << (i << 3);
            }
            return Convert.ChangeType(ret, t.GetType());
        }

        static string chex(object t) // Convert a ushort, uint or ulong to a string representing it in hex
        {
            int size = awesome(t); // get the size of the type of object passed
            string r = ""; // return string
            ulong x = Convert.ToUInt64(t); // make t more meaningful
            string hex = "0123456789ABCDEF"; // hex chars used for the conversion

            for(int i = 0; i < size; i++) // go through all bytes in the value passed, convert them to hex strings
            {
                r = (hex[(int)((x >> 4) & 0xf)] + "") + (hex[(int)(x & 0xf)] + "") + r;
                x >>= 8; // make way for the next byte
            }

            return r;
        }

        static byte swapEndian(byte x) // reverse the byte order of a byte
        {
            byte r = 0;
            for (int i = 0; i < sizeof(byte); i++)
            {
                r |= (byte)(((x >> ((i ^ (sizeof(byte) - 1)) << 3)) & 0xff) << (i << 3));
            }
            return r;
        }

        static ushort swapEndian(ushort x) // reverse the byte order of a ushort
        {
            ushort r = 0;
            for (int i = 0; i < sizeof(ushort); i++)
            {
                r |= (ushort)(((x >> ((i ^ (sizeof(ushort) - 1)) << 3)) & 0xff) << (i << 3));
            }
            return r;
        }

        static uint swapEndian(uint x) // reverse the byte order of a uint
        {
            uint r = 0;
            for (int i = 0; i < sizeof(uint); i++)
            {
                r |= (uint)(((x >> ((i ^ (sizeof(uint) - 1)) << 3)) & 0xff) << (i << 3));
            }
            return r;
        }

        static ulong swapEndian(ulong x) // reverse the byte order of a ulong
        {
            ulong r = 0;
            for (int i = 0; i < sizeof(ulong); i++)
            {
                r |= (ulong)(((x >> ((i ^ (sizeof(ulong) - 1)) << 3)) & 0xff) << (i << 3));
            }
            return r;
        }

        static void Main(string[] args)
        {
            // Testing the generic one
            object[] t = new object[] { (byte)0xE2, (ushort)0xFFAA, (uint)0xFFA23BC4, (ulong)0xFFFFFFFFFFA23BC4 };
            for (int i = 0; i < t.Length; i++)
                Console.Write("{0}\n", chex(swapEndian_g(t[i])));
            Console.Write("\n\n");

            // Testing the separate functions that use explicit types
            Console.Write("{0}\n", chex(swapEndian((byte)0xE2)));
            Console.Write("{0}\n", chex(swapEndian((ushort)0xFFAA)));
            Console.Write("{0}\n", chex(swapEndian((uint)0xFFA23BC4)));
            Console.Write("{0}\n", chex(swapEndian((ulong)0xFFFFFFFFFFA23BC4)));

            Console.ReadKey(true);
        }
    }
}

paulguy
Zealot
Posts: 1076
Joined: Sat Jul 02, 2005 2:01 am
Contact:

Re: Ways of reversing the byte order of an unsigned integer

Post by paulguy »

When I was younger, I had to make a thing in qbasic to split the bits from a 16 bit word and rearrange them in to two 8 bit bytes, since I didn't know how to read strings from files, and would only read 16 bits at a time in binary mode. I did it all mathematically, too. I pretty much took the way humans are taught to split and recombine in binary and implemented it in code. :p It was surprisingly quick... the slowest part was disk access.

I remember doing this to get directory listings, by issuing a "dir /b" to the shell. Not quite what you're referring to, but could've been adapted for the purpose... I don't think I have it on HERE but I might have a backup CD with it on there in the basement. What it went in to was a map loading frontend for duke nukem 3d because I had too many for the setup program to display and I couldn't get on the internet at the time (phone nazi grandmother) to download a frontend.

As for posting something, I might make something in C, but I'm not a great programmer so it'll just be some shifts and ORs, nothing crazy-optimized or anything.
Maybe these people were born without that part of their brain that lets you try different things to see if they work better. --Retsupurae
grinvader
ZSNES Shake Shake Prinny
Posts: 5632
Joined: Wed Jul 28, 2004 4:15 pm
Location: PAL50, dood !

Re: Ways of reversing the byte order of an unsigned integer

Post by grinvader »

lordmister wrote:Here is mine, in C#, that reverses the byte order of a ushort, uint or ulong,
...

i'd post something but then you'd have to kill yourself due to how suck your code is in comparison





which sorta makes me want to post it



but i'd rather pull a saturn and watch you wriggle in suckiness lawl
皆黙って俺について来い!!

Code: Select all

<jmr> bsnes has the most accurate wiki page but it takes forever to load (or something)
Pantheon: Gideon Zhi | CaitSith2 | Nach | kode54
lordmissus
Ignorant Child
Posts: 326
Joined: Mon Apr 06, 2009 10:10 pm
Location: 1984

Re: Ways of reversing the byte order of an unsigned integer

Post by lordmissus »

Post it, then.
Also, my code doesn't suck.
creaothceann
Seen it all
Posts: 2302
Joined: Mon Jan 03, 2005 5:04 pm
Location: Germany
Contact:

Re: Ways of reversing the byte order of an unsigned integer

Post by creaothceann »

lordmister wrote:my code doesn't suck.
No, your code is
lordmister wrote:static int awesome(object t)
.
vSNES | Delphi 10 BPLs
bsnes launcher with recent files list
lordmissus
Ignorant Child
Posts: 326
Joined: Mon Apr 06, 2009 10:10 pm
Location: 1984

Re: Ways of reversing the byte order of an unsigned integer

Post by lordmissus »

...

Code: Select all

        static ushort swapEndian(ushort x) // reverse the byte order of a ushort
        {
#if SIZEOF_USHORT_IS_2
            return (ushort)(((x & 0xFF) << 8) | (x >> 8));
#else
            ushort r = 0;
            for (int i = 0; i < sizeof(ushort); i++)
            {
                r |= (ushort)(((x >> ((i ^ (sizeof(ushort) - 1)) << 3)) & 0xff) << (i << 3));
            }
            return r;
#endif
        }

        static uint swapEndian(uint x) // reverse the byte order of a uint
        {
#if SIZEOF_UINT_IS_4
   		    x = (x >> 16) | (x << 16);
		    return ((x & 0xFF00FF00) >> 8) | ((x & 0x00FF00FF) << 8);
#else
            uint r = 0;
            for (int i = 0; i < sizeof(uint); i++)
            {
                r |= (uint)(((x >> ((i ^ (sizeof(uint) - 1)) << 3)) & 0xff) << (i << 3));
            }
            return r;
#endif
        }

        static ulong swapEndian(ulong x) // reverse the byte order of a ulong
        {
#if SIZEOF_ULONG_IS_8
            x = (x >> 32) | (x << 32);
            x = ((x & 0xFFFF0000FFFF0000) >> 16) | ((x & 0x0000FFFF0000FFFF) << 16);
            return ((x & 0xFF00FF00FF00FF00) >> 8) | ((x & 0x00FF00FF00FF00FF) << 8);
#else
            ulong r = 0;
            for (int i = 0; i < sizeof(ulong); i++)
            {
                r |= (ulong)(((x >> ((i ^ (sizeof(ulong) - 1)) << 3)) & 0xff) << (i << 3));
            }
            return r;
#endif
        }
grinvader
ZSNES Shake Shake Prinny
Posts: 5632
Joined: Wed Jul 28, 2004 4:15 pm
Location: PAL50, dood !

Re: Ways of reversing the byte order of an unsigned integer

Post by grinvader »

lordmister wrote:Post it, then.
what part of lulz did you miss
皆黙って俺について来い!!

Code: Select all

<jmr> bsnes has the most accurate wiki page but it takes forever to load (or something)
Pantheon: Gideon Zhi | CaitSith2 | Nach | kode54
lordmissus
Ignorant Child
Posts: 326
Joined: Mon Apr 06, 2009 10:10 pm
Location: 1984

Re: Ways of reversing the byte order of an unsigned integer

Post by lordmissus »

If I wanted to write fast code I would. However,

Code: Select all

#define SIZEOF_USHORT_IS_2
#define SIZEOF_UINT_IS_4
#define SIZEOF_ULONG_IS_8

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{

    class Program
    {
        static int[] sizes = new int[] // sizes that can be returned
            { 
                sizeof(byte), sizeof(ushort), sizeof(uint), sizeof(ulong), 
            };

        static int sizeIndex(object t) // take a ushort, uint or ulong passed as an object, 
                                     // and return the size in bytes of the type actually passed
        {
            object[] types = new object[]  // supported types are:
            { 
                new byte(), new ushort(), new uint(), new ulong() 
            };
            int index = 0; // This is used for the return value

            for (int i = 0; !types[index = i++].GetType().IsInstanceOfType(t); ) // determine the type
                if (i >= types.Length) // if this is the case, an unsupported type was passed
                    throw new Exception("awesome(object t) ERROR! UNSUPPORTED TYPE ''''" + t.GetType() + "''''. Stop");

            return index; // return the index for the size
        }

        delegate ulong ptr(ulong x);
        static ulong sw8(ulong x) { return byteSwapEndian((byte)x); }
        static ulong sw16(ulong x) { return ushrSwapEndian((ushort)x); }
        static ulong sw32(ulong x) { return uintSwapEndian((uint)x); }
        static ulong sw64(ulong x) { return ulngSwapEndian((ulong)x); }
        static ptr[] sw_table = new ptr[]
        {
            sw8, sw16, sw32, sw64
        };

        static object swapEndian_g(object t) // reverse the byte order of a generic type (can be ushort, uint or ulong)
        {                                    // Using this is slow, but it supports all the types you need, and it's use of awesome features in C# is awesome
            return Convert.ChangeType(sw_table[sizeIndex(t)].Invoke(Convert.ToUInt64(t)), t.GetType());
        }

        static string chex(object t) // Convert a ushort, uint or ulong to a string representing it in hex
        {
            int size = sizes[sizeIndex(t)]; // get the size of the type of object passed
            string r = ""; // return string
            ulong x = Convert.ToUInt64(t); // make t more meaningful
            string hex = "0123456789ABCDEF"; // hex chars used for the conversion

            for(int i = 0; i < size; i++) // go through all bytes in the value passed, convert them to hex strings
            {
                r = (hex[(int)((x >> 4) & 0xf)] + "") + (hex[(int)(x & 0xf)] + "") + r;
                x >>= 8; // make way for the next byte
            }

            return r;
        }

        static byte byteSwapEndian(byte x) // reverse the byte order of a byte
        {
            return x; // what were you thinking would happen?
        }

        static ushort ushrSwapEndian(ushort x) // reverse the byte order of a ushort
        {
#if SIZEOF_USHORT_IS_2
            return (ushort)(((x & 0xFF) << 8) | (x >> 8));
#else
            ushort r = 0;
            for (int i = 0; i < sizeof(ushort); i++)
            {
                r |= (ushort)(((x >> ((i ^ (sizeof(ushort) - 1)) << 3)) & 0xff) << (i << 3));
            }
            return r;
#endif
        }

        static uint uintSwapEndian(uint x) // reverse the byte order of a uint
        {
#if SIZEOF_UINT_IS_4
   		    x = (x >> 16) | (x << 16);
		    return ((x & 0xFF00FF00) >> 8) | ((x & 0x00FF00FF) << 8);
#else
            uint r = 0;
            for (int i = 0; i < sizeof(uint); i++)
            {
                r |= (uint)(((x >> ((i ^ (sizeof(uint) - 1)) << 3)) & 0xff) << (i << 3));
            }
            return r;
#endif
        }

        static ulong ulngSwapEndian(ulong x) // reverse the byte order of a ulong
        {
#if SIZEOF_ULONG_IS_8
            x = (x >> 32) | (x << 32);
            x = ((x & 0xFFFF0000FFFF0000) >> 16) | ((x & 0x0000FFFF0000FFFF) << 16);
            return ((x & 0xFF00FF00FF00FF00) >> 8) | ((x & 0x00FF00FF00FF00FF) << 8);
#else
            ulong r = 0;
            for (int i = 0; i < sizeof(ulong); i++)
            {
                r |= (ulong)(((x >> ((i ^ (sizeof(ulong) - 1)) << 3)) & 0xff) << (i << 3));
            }
            return r;
#endif
        }

        static void Main(string[] args)
        {
            // Testing the generic one
            object[] t = new object[] { (byte)0xE2, (ushort)0xFFAA, (uint)0xFFA23BC4, (ulong)0xFFFFFFFFFFA23BC4 };
            for (int i = 0; i < t.Length; i++)
                Console.Write("{0}\n", chex(swapEndian_g(t[i])));
            Console.Write("\n\n");

            // Testing the separate functions that use explicit types
            Console.Write("{0}\n", chex(byteSwapEndian((byte)0xE2)));
            Console.Write("{0}\n", chex(ushrSwapEndian((ushort)0xFFAA)));
            Console.Write("{0}\n", chex(uintSwapEndian((uint)0xFFA23BC4)));
            Console.Write("{0}\n", chex(ulngSwapEndian((ulong)0xFFFFFFFFFFA23BC4)));

            Console.ReadKey(true);
        }
    }
}
Last edited by lordmissus on Sat Apr 24, 2010 4:10 pm, edited 1 time in total.
paulguy
Zealot
Posts: 1076
Joined: Sat Jul 02, 2005 2:01 am
Contact:

Re: Ways of reversing the byte order of an unsigned integer

Post by paulguy »

C version. Probably faster than his version even by merit of being in a lower level language and it's easily readable, unlike his. :)

Code: Select all

#include <stdio.h>
#include <stdlib.h>

// ABCD -> CDAB

inline short int swapShort(short int num) {
	return((num << 8) | (num >> 8));
}

// ABCDEFGH -> GHEFCDAB

inline int swapInt(int num) {
	return(	(num >> 24) |
		((num & 0x00FF0000) >> 8) |
		((num & 0x0000FF00) << 8) |
		(num << 24) );
}

// ABCDEFGHJKLMNOPQ -> PQNOLMJKGHEFCDAB

inline long int swapLong(long int num) {
	return(	(num >> 56) |
		((num & 0x00FF000000000000) >> 40) |
		((num & 0x0000FF0000000000) >> 24) |
		((num & 0x000000FF00000000) >> 8) |
		((num & 0x00000000FF000000) << 8) |
		((num & 0x0000000000FF0000) << 24) |
		((num & 0x000000000000FF00) << 40) |
		(num << 56) );
}

// swap anything

void swapVar(char *num, size_t size) {
	char t;
	int i, c;
	c = size / 2;
	for(i = 0; i < c; i++) {
		t = num[i];
		num[i] = num[size - i - 1];
		num[size - i - 1] = t;
	}
}

// display any length number as hex

char *toHex(unsigned char *num, size_t size) {
	char *out;
	char lookup[] = "0123456789ABCDEF";
	int i, t;

	out = (char *)malloc(sizeof(char) * (size * 2 + 1));

	for(i = 0; i < size; i++) {
		t = i * 2;
		out[t] = lookup[num[i] >> 4];
		out[t + 1] = lookup[num[i] & 0x0F];
	}

	out[size * 2] = '\0';
	return(out);
}

int main(int argc, char **argv) {
	short int a = 0x0123;
	int b = 0x01234567;
	long int c = 0x0123456789ABCDEF;
	char d[] = {	0x00, 0x01, 0x12, 0x23, 0x34, 0x45, 0x56, 0x67,
			0x78, 0x89, 0x9A, 0xAB, 0xBC, 0xCD, 0xDE, 0xEF };
	char *hex;

	printf("Swap Bytes test\n\n");

	printf("16bit short int: ");
	hex = toHex(&a, sizeof(short int));
	printf("%s --> ", hex);
	free(hex);
	a = swapShort(a);
	hex = toHex(&a, sizeof(short int));
	printf("%s\n", hex);
	free(hex);

	printf("32bit int: ");
	hex = toHex(&b, sizeof(int));
	printf("%s --> ", hex);
	free(hex);
	b = swapInt(b);
	hex = toHex(&b, sizeof(int));
	printf("%s\n", hex);
	free(hex);
	
	printf("64bit long int: ");
	hex = toHex(&c, sizeof(long int));
	printf("%s --> ", hex);
	free(hex);
	c = swapLong(c);
	hex = toHex(&c, sizeof(long int));
	printf("%s\n", hex);
	free(hex);

	printf("Variable size [128bit]: ");
	hex = toHex(d, 16);
	printf("%s --> ", hex);
	free(hex);
	swapVar(d, 16);
	hex = toHex(d, 16);
	printf("%s\n", hex);
	free(hex);

	exit(0);
}
Maybe these people were born without that part of their brain that lets you try different things to see if they work better. --Retsupurae
lordmissus
Ignorant Child
Posts: 326
Joined: Mon Apr 06, 2009 10:10 pm
Location: 1984

Re: Ways of reversing the byte order of an unsigned integer

Post by lordmissus »

Changed a few of the names, and moved things around to make it more readable:

Code: Select all

#define SIZEOF_USHORT_IS_2
#define SIZEOF_UINT_IS_4
#define SIZEOF_ULONG_IS_8

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{

    class Program
    {

        delegate ulong ptr(ulong x);
        static ulong sw8(ulong x) { return swapEndian((byte)x); }
        static ulong sw16(ulong x) { return swapEndian((ushort)x); }
        static ulong sw32(ulong x) { return swapEndian((uint)x); }
        static ulong sw64(ulong x) { return swapEndian((ulong)x); }
        static ptr[] sw_table = new ptr[]
        {
            sw8, sw16, sw32, sw64
        };

        static int[] sizes = new int[] // sizes that can be returned
            { 
                sizeof(byte), sizeof(ushort), sizeof(uint), sizeof(ulong), 
            };

        static int sizeIndex(object t) // take a ushort, uint or ulong passed as an object, 
                                     // and return the size in bytes of the type actually passed
        {
            object[] types = new object[]  // supported types are:
            { 
                new byte(), new ushort(), new uint(), new ulong() 
            };
            int index = 0; // This is used for the return value

            for (int i = 0; !types[index = i++].GetType().IsInstanceOfType(t); ) // determine the type
                if (i >= types.Length) // if this is the case, an unsupported type was passed
                    throw new Exception("awesome(object t) ERROR! UNSUPPORTED TYPE ''''" + t.GetType() + "''''. Stop");

            return index; // return the index for the size
        }

        static object swapEndian(object t) // reverse the byte order of a generic type (can be ushort, uint or ulong)
        {                                    // Using this is slow, but it supports all the types you need, and it's use of awesome features in C# is awesome
            return Convert.ChangeType(sw_table[sizeIndex(t)].Invoke(Convert.ToUInt64(t)), t.GetType());
        }

        static byte swapEndian(byte x) // reverse the byte order of a byte
        {
            return x; // what were you thinking would happen?
        }

        static ushort swapEndian(ushort x) // reverse the byte order of a ushort
        {
#if SIZEOF_USHORT_IS_2
            return (ushort)(((x & 0xFF) << 8) | (x >> 8));
#else
            ushort r = 0;
            for (int i = 0; i < sizeof(ushort); i++)
            {
                r |= (ushort)(((x >> ((i ^ (sizeof(ushort) - 1)) << 3)) & 0xff) << (i << 3));
            }
            return r;
#endif
        }

        static uint swapEndian(uint x) // reverse the byte order of a uint
        {
#if SIZEOF_UINT_IS_4
   		    x = (x >> 16) | (x << 16);
		    return ((x & 0xFF00FF00) >> 8) | ((x & 0x00FF00FF) << 8);
#else
            uint r = 0;
            for (int i = 0; i < sizeof(uint); i++)
            {
                r |= (uint)(((x >> ((i ^ (sizeof(uint) - 1)) << 3)) & 0xff) << (i << 3));
            }
            return r;
#endif
        }

        static ulong swapEndian(ulong x) // reverse the byte order of a ulong
        {
#if SIZEOF_ULONG_IS_8
            x = (x >> 32) | (x << 32);
            x = ((x & 0xFFFF0000FFFF0000) >> 16) | ((x & 0x0000FFFF0000FFFF) << 16);
            return ((x & 0xFF00FF00FF00FF00) >> 8) | ((x & 0x00FF00FF00FF00FF) << 8);
#else
            ulong r = 0;
            for (int i = 0; i < sizeof(ulong); i++)
            {
                r |= (ulong)(((x >> ((i ^ (sizeof(ulong) - 1)) << 3)) & 0xff) << (i << 3));
            }
            return r;
#endif
        }

        static string chex(object t) // Convert a ushort, uint or ulong to a string representing it in hex
        {
            int size = sizes[sizeIndex(t)]; // get the size of the type of object passed
            string r = ""; // return string
            ulong x = Convert.ToUInt64(t); // make t more meaningful
            string hex = "0123456789ABCDEF"; // hex chars used for the conversion

            for (int i = 0; i < size; i++) // go through all bytes in the value passed, convert them to hex strings
            {
                r = (hex[(int)((x >> 4) & 0xf)] + "") + (hex[(int)(x & 0xf)] + "") + r;
                x >>= 8; // make way for the next byte
            }

            return r;
        }

        static void Main(string[] args)
        {
            // Testing the generic one
            object[] t = new object[] { (byte)0xE2, (ushort)0xFFAA, (uint)0xFFA23BC4, (ulong)0xFFFFFFFFFFA23BC4 };
            for (int i = 0; i < t.Length; i++)
                Console.Write("{0}\n", chex(swapEndian(t[i])));
            Console.Write("\n\n");

            // Testing the separate functions that use explicit types
            Console.Write("{0}\n", chex(swapEndian((byte)0xE2)));
            Console.Write("{0}\n", chex(swapEndian((ushort)0xFFAA)));
            Console.Write("{0}\n", chex(swapEndian((uint)0xFFA23BC4)));
            Console.Write("{0}\n", chex(swapEndian((ulong)0xFFFFFFFFFFA23BC4)));

            Console.ReadKey(true);
        }
    }
}
(NOTE: The point of these threads is to post complex code. Speed is irrelevant; you are encouraged to come up with as many strange and esoteric ways as possible to perform a given operation. Think "swatting a fly with a bazooka").
Rashidi
Trooper
Posts: 515
Joined: Fri Aug 18, 2006 2:45 pm

Re: Ways of reversing the byte order of an unsigned integer

Post by Rashidi »

i prefer:

XCHG AH,AL
;or
BSWAP EAX
lordmissus
Ignorant Child
Posts: 326
Joined: Mon Apr 06, 2009 10:10 pm
Location: 1984

Re: Ways of reversing the byte order of an unsigned integer

Post by lordmissus »

Also,

Code: Select all

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{

    class Program
    {
        static ushort swapEndian(ushort x) // reverse the byte order of a ushort
        {
            return (ushort)(((x & 0xFF) << 8) | (x >> 8));
        }

        static uint swapEndian(uint x) // reverse the byte order of a uint
        {
   		    x = (x >> 16) | (x << 16);
		    return ((x & 0xFF00FF00) >> 8) | ((x & 0x00FF00FF) << 8);
        }

        static ulong swapEndian(ulong x) // reverse the byte order of a ulong
        {
            x = (x >> 32) | (x << 32);
            x = ((x & 0xFFFF0000FFFF0000) >> 16) | ((x & 0x0000FFFF0000FFFF) << 16);
            return ((x & 0xFF00FF00FF00FF00) >> 8) | ((x & 0x00FF00FF00FF00FF) << 8);
        }

        static string chex(object t) // Convert a ushort, uint or ulong to a string representing it in hex
        {
            int[] sizes = new int[] { sizeof(byte), sizeof(ushort), sizeof(uint), sizeof(ulong) };
            object[] types = new object[] { new byte(), new ushort(), new uint(), new ulong() };

            int index = 0; // This is used for the return value

            for (int i = 0; !types[index = i++].GetType().IsInstanceOfType(t); ) // determine the type
                if (i >= types.Length) // if this is the case, an unsupported type was passed
                    throw new Exception("awesome(object t) ERROR! UNSUPPORTED TYPE ''''" + t.GetType() + "''''. Stop");

            index = sizes[index];

            string r = ""; // return string
            ulong x;
            
                x = Convert.ToUInt64(t); // make t more meaningful

            string hex = "0123456789ABCDEF"; // hex chars used for the conversion

            for (int i = 0; i < index; i++) // go through all bytes in the value passed, convert them to hex strings
            {
                r = (hex[(int)((x >> 4) & 0xf)] + "") + (hex[(int)(x & 0xf)] + "") + r;
                x >>= 8; // make way for the next byte
            }

            return r;
        }

        static void Main(string[] args)
        {
            unchecked // For "fes": this should output two lines saying 0. Change this to checked and VS2010 complains
            {
                Console.Write(
                    "{0}\n{1}\n\n", 
                    (int)(int)((int)0 - 1) ^ (int)((int)0 - 1), 
                    (uint)(int)((int)0 - 1) ^ (uint)((int)0 - 1)
                );
            }
               
            // Testing the separate functions that use explicit types
            Console.Write("{0}\n", chex(swapEndian((ushort)0xFFAA)));
            Console.Write("{0}\n", chex(swapEndian((uint)0xFFA23BC4)));
            Console.Write("{0}\n", chex(swapEndian((ulong)0xFFFFFFFFFFA23BC4)));

            Console.ReadKey(true);
        }
    }
}

grinvader
ZSNES Shake Shake Prinny
Posts: 5632
Joined: Wed Jul 28, 2004 4:15 pm
Location: PAL50, dood !

Re: Ways of reversing the byte order of an unsigned integer

Post by grinvader »

lordmister wrote:If I wanted to write fast code I would.
just keep telling yourself that


(NOTE: The point of these threads is to post complex code. Speed is irrelevant; you are encouraged to come up with as many strange and esoteric ways as possible to perform a given operation. Think "swatting a fly with a bazooka").
an exercise in stupidity then ? have fun


P.S. the edit button. use it.
皆黙って俺について来い!!

Code: Select all

<jmr> bsnes has the most accurate wiki page but it takes forever to load (or something)
Pantheon: Gideon Zhi | CaitSith2 | Nach | kode54
lordmissus
Ignorant Child
Posts: 326
Joined: Mon Apr 06, 2009 10:10 pm
Location: 1984

Re: Ways of reversing the byte order of an unsigned integer

Post by lordmissus »

x86 is little endian. I happen to be on a x86_64 (running 32-bit OS) machine. So,

Code: Select all

        unsafe static ushort swapEndian(ushort x) // reverse the byte order of a ushort
        {
            unchecked
            {
                byte* r = (byte*)&x;

                ushort ret = 0;
                ushort* pRet = &ret;

                *pRet |= *r;
                ++r;

                return (ushort)((*pRet <<= 8) | *r);
            }
        }

        unsafe static uint swapEndian(uint x) // reverse the byte order of a uint
        {
            unchecked
            {
                uint t = x;
                uint* a = &t;
                *a &= 0;

                byte* r = (byte*)&x - 1;
                for(int i = 0; i < 4; i++)
                {
                    *a |= *r;
                    *a <<= 8;
                    ++r;
                }

                return *a | *r;
            }
        }

        unsafe static ulong swapEndian(ulong x) // reverse the byte order of a ulong
        {
            unchecked
            {
                byte* t = (byte*)&x - 1;

                ulong b = x;
                ulong* k = &b;

                *k &= 0;

                for(int i = 0; i < 8; i++)
                {
                    *k |= *t;
                    *k <<= 8;
                    ++t;
                }

                return *k | *t;
            }
        }
EDIT:

Code: Select all

        unsafe static uint swapEndian(uint* x) // reverse the byte order of a uint
        {
            unchecked
            {
                byte* ptr = (byte*)x;

                byte t = 0;
                byte* tmp = &t;

                for(int i = 0; i < 2; i++)
                {
                    *tmp = *ptr;
                    *ptr = *(ptr + (i ^ 3) - i);
                    *(ptr + (i ^ 3) - i) = *tmp;
                    ++ptr;
                }

                return 0;
            }
        }
EDIT:

Code: Select all

        unsafe static void swapEndian(ushort* x) // reverse the byte order of a ushort
        {
            unchecked
            {
                byte* ptr = (byte*)x;

                byte t = 0;
                byte* tmp = &t;

                *tmp = *ptr;
                *ptr = *++ptr;
                *ptr = *tmp;
            }
        }

        unsafe static void swapEndian(uint* x) // reverse the byte order of a uint
        {
            unchecked
            {
                byte* ptr = (byte*)x;

                byte t = 0;
                byte* tmp = &t;

                *tmp = *ptr;
                *ptr = *(ptr + 3);
                *(ptr + 3) = *tmp;

                *tmp = *++ptr;
                *ptr = *(ptr++ + 1);
                *ptr = *tmp;
            }
        }
PHoNyMiKe
Retrosexual
Posts: 1011
Joined: Wed Jul 28, 2004 2:09 am
Location: Rapture

Re: Ways of reversing the byte order of an unsigned integer

Post by PHoNyMiKe »

8 bit assembly for the Atmel ATtiny26: 2KB flash memory, 128 bytes of sram, 128 bytes of eeprom, speed of chip: up to 16 MHz.

Code: Select all

byteswap:		;XL = location of bytes in sram (0x60 - 0xDF), r16 = number of bytes to swap (1 - 4)
	push	r16		;put stuff aside
	push	r17
	push	r18
	push	XL
	
	loop:
	ld		r17, X+	;grab bytes from sram
	ld		r18, X+
	st		-X, r17	;put bytes back in sram swapped
	st		-X, r18

	adiw	X, 2	;inc memory pointer to next set of bytes

	subi	r16, 1	;keep looping if bytes are left to swap
	brne	loop

	pop		XL		;put stuff back the way we found it
	pop		r18
	pop		r17
	pop		r16

	ret
[url=http://www.alexchiu.com/affiliates/clickthru.cgi?id=phonymike]ultimate immortality[/url]
[url=http://www.sloganizer.net/en/][img]http://www.sloganizer.net/en/image,zsnes,white,purple.png[/img][/url]
lordmissus
Ignorant Child
Posts: 326
Joined: Mon Apr 06, 2009 10:10 pm
Location: 1984

Re: Ways of reversing the byte order of an unsigned integer

Post by lordmissus »

So I'm thinking. If x86 stores values in little endian byte order, I don't need to reverse the order when wanting to display an unsigned integer in hex, with the bytes reverse. I just setup a byte* to the first byte in the unsigned integer, and read all the bytes in succession. For displaying the hex where the bytes are instead in big endian order, I read all the bytes from the end to the beginning, in succession.

So,

Code: Select all

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    unsafe class Program
    {
        unsafe static int getSize(object t)
        {
            unchecked
            {
                int[] sizes = new int[] { sizeof(byte), sizeof(ushort), sizeof(uint), sizeof(ulong) };
                object[] types = new object[] { new byte(), new ushort(), new uint(), new ulong() };

                int index = 0; // This is used for the return value

                for (int i = 0; !types[index = i++].GetType().IsInstanceOfType(t); ) // determine the type
                    if (i >= types.Length) // if this is the case, an unsupported type was passed
                        throw new Exception("awesome(object t) ERROR! UNSUPPORTED TYPE ''''" + t.GetType() + "''''. Stop");

                return sizes[index];
            }
        }
        // Output the hex string of an unsigned type with the bytes in reversed (little endian) or non-reversed (big endian) byte order
        unsafe static string chex(object t, bool lEndian)
        {
            unchecked
            {
                int size = getSize(t);

                string r = ""; // return string
                string hex = "0123456789ABCDEF";

                ulong x = Convert.ToUInt64(t); // make t more meaningful
                byte* ptr = (byte*)&x + (lEndian ? 0 : size - 1);

                for (int i = 0; i < size; i++)
                {
                    r += hex[(*ptr) >> 4] + "" + hex[(*ptr) & 0x0F] + "";
                    if (lEndian) ++ptr; else --ptr;
                }

                return r;
            }
        }
        unsafe static void Main(string[] args)
        {
            unchecked
            {
                Console.ForegroundColor = ConsoleColor.Green;

                Console.Write("Pointer exercise using Visual C#\n\n");
                Console.Write("Here we are displaying first a ushort, then a uint then a ulong.\n" + 
                              "We display firstly the values in the order they appear when displaying them,\n" + 
                              "and then we are displaying them in the order they are stored on x86, i.e. little endian\n\n");

                object[] v = new object[] { (byte)0xE2, (ushort)0xFFAA, (uint)0xFFA23BC4, (ulong)0xFFFFFFFFFFA23BC4 };
                for(int i = 0; i < v.Length; i++)
                {
                    Console.Write("Type: {0}\n", v[i].GetType());
                    Console.Write("original: {0}\n", chex(v[i], false));
                    Console.Write("reversed: {0} (this is how the integer is stored in memory)\n\n", chex(v[i], true));
                }
                Console.Write("Press a key to continue\n");

                Console.ReadKey(true);
            }
        }
    }
}
lordmissus
Ignorant Child
Posts: 326
Joined: Mon Apr 06, 2009 10:10 pm
Location: 1984

Re: Ways of reversing the byte order of an unsigned integer

Post by lordmissus »

So, what if the user is running .NET on a big endian system? I'm assuming the situation would be different. Thus,

Code: Select all

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

// The following program is endian-independant. I.e. it will work on any little or big endian CPU that .NET happens to be running on.
// The assumption is that .NET doesn't store bytes in it's own order, instead using the order of the native CPU that
// said .NET implementation is running on.

// It uses unsafe code, so beware when using this program. The GC really likes moving pointers around sometimes... I'd used the "fixed"
// keyword, but I'm moving pointers around myself, so I just need to be willing to take that risk

namespace ConsoleApplication1
{
    unsafe class Program
    {
        unsafe static int getSize(object t)
        {
            unchecked
            {
                int[] sizes = new int[] { sizeof(byte), sizeof(ushort), sizeof(uint), sizeof(ulong) };
                object[] types = new object[] { new byte(), new ushort(), new uint(), new ulong() };

                int index = 0; // This is used for the return value

                for (int i = 0; !types[index = i++].GetType().IsInstanceOfType(t); ) // determine the type
                    if (i >= types.Length) // if this is the case, an unsupported type was passed
                        throw new Exception("awesome(object t) ERROR! UNSUPPORTED TYPE ''''" + t.GetType() + "''''. Stop");

                return sizes[index];
            }
        }
        unsafe static bool isLittleEndian() // Establishes whether the machine .NET is running on is little endian
        {
            unchecked
            {
                ushort x = 0xFFAA;
                byte* ptr = (byte*)&x;
                return 0xAA == *ptr;
            }
        }
        // Output the hex string of an unsigned type with the bytes in reversed 
        // (how the computer stores it) and logical (how a human will see it) byte order
        unsafe static string chex(object t, bool reverse)
        {
            unchecked
            {
                int size = getSize(t);

                bool lEndian = isLittleEndian(); // check which byte order the native CPU uses in memory
                reverse ^= !lEndian;

                string r = ""; // return string
                string hex = "0123456789ABCDEF";

                ulong x = Convert.ToUInt64(t); // make t more meaningful
                byte* ptr = (byte*)&x + (reverse ? 0 : (lEndian ? size - 1 : 0));

                for (int i = 0; i < size; i++)
                {
                    r += hex[(*ptr) >> 4] + "" + hex[(*ptr) & 0x0F] + "";
                    if (reverse||(!lEndian)) ++ptr; else --ptr;
                }

                return r;
            }
        }
        unsafe static void test()
        {
            unchecked
            {
                Console.SetWindowSize(80, 50);
                Console.ForegroundColor = ConsoleColor.Green;

                Console.Write("Pointer exercise using Visual C#\n\n");
                Console.Write("Here we are displaying first a ushort, then a uint then a ulong.\n" +
                              "We display firstly the values in the order they appear when displaying them,\n" +
                              "and then we are displaying them in the order they are stored on x86, \n(i.e. little endian).\n\n" +
                              "This program is endian-independant, however, so it won't matter if your\n" +
                              ".NET implementation is running on a big endian machine.\n\n");

                object[] v = new object[] { (byte)0xE2, (ushort)0xFFAA, (uint)0xFFA23BC4, (ulong)0xFFFFFFFFFFA23BC4 };
                for (int i = 0; i < v.Length; i++)
                {
                    Console.Write("Type: {0}\n", v[i].GetType());
                    Console.Write("original: {0}\n", chex(v[i], false));
                    Console.Write("reversed: {0} (this is how the integer is stored in memory)\n\n", chex(v[i], true));
                }
                Console.Write("Press a key to continue\n");
            }
        }
        unsafe static int Main(string[] args)
        {
            unchecked
            {
                test();
                Console.ReadKey(true);
                return 0;
            }
        }
    }
}
When running the program, with .NET running under Windows XP MCE (which is x86) on my x86-based PC, I get the following output:

Code: Select all

Pointer exercise using Visual C#

Here we are displaying first a ushort, then a uint then a ulong.
We display firstly the values in the order they appear when displaying them,
and then we are displaying them in the order they are stored on x86,
(i.e. little endian).

This program is endian-independant, however, so it won't matter if your
.NET implementation is running on a big endian machine.

Type: System.Byte
original: E2
reversed: E2 (this is how the integer is stored in memory)

Type: System.UInt16
original: FFAA
reversed: AAFF (this is how the integer is stored in memory)

Type: System.UInt32
original: FFA23BC4
reversed: C43BA2FF (this is how the integer is stored in memory)

Type: System.UInt64
original: FFFFFFFFFFA23BC4
reversed: C43BA2FFFFFFFFFF (this is how the integer is stored in memory)

Press a key to continue
According to my theory, I should get the following output if I was to run this under an implementation of .NET that is running on a big endian system (e.g. PowerPC-based systems):

Code: Select all

Pointer exercise using Visual C#

Here we are displaying first a ushort, then a uint then a ulong.
We display firstly the values in the order they appear when displaying them,
and then we are displaying them in the order they are stored on x86,
(i.e. little endian).

This program is endian-independant, however, so it won't matter if your
.NET implementation is running on a big endian machine.

Type: System.Byte
original: E2
reversed: E2 (this is how the integer is stored in memory)

Type: System.UInt16
original: FFAA
reversed: FFAA (this is how the integer is stored in memory)

Type: System.UInt32
original: FFA23BC4
reversed: FFA23BC4 (this is how the integer is stored in memory)

Type: System.UInt64
original: FFFFFFFFFFA23BC4
reversed: FFFFFFFFFFA23BC4 (this is how the integer is stored in memory)

Press a key to continue
but I have yet to test this theory, as I lack a PPC-based machine. I had Linux on my PS3 some time ago, and the PS3 uses a Cell processor, which irrc is based on PowerPC, but I don't have Linux on it anymore. I also can't test it now, since I installed that update that disables Linux on PS3...

This program should also work correctly regardless of the size in bytes of the various types. I am assuming that it is always the same, since we have IntPtr for that, that and it wouldn't make sense so definite sizeof(UInt64) to be, say, 16, despite it being called UInt64, which would instantly tell you, "hmm, 64 / 8 = 8, sizeof(ulong) must be 8". I assume nothing.
lordmissus
Ignorant Child
Posts: 326
Joined: Mon Apr 06, 2009 10:10 pm
Location: 1984

Re: Ways of reversing the byte order of an unsigned integer

Post by lordmissus »

Here is a better version of the chex function above. It is more code, but should be slightly faster, and is optimized for maximum readability.
The last version, based on a dry run I did, did not work afterall in the event that the bytes are stored in big endian order. This code probably will (though, again, I will mention that I have no means to test it in the real world). Thus,

Code: Select all

        // Output the hex string of an unsigned type with the bytes in reversed 
        // (how the computer stores it) and logical (how a human will see it) byte order
        unsafe static string chex(object t, bool physical)
        {               // physical represents whether or not the integer is to be displayed in the
            unchecked   // byte-order in which it is literally stored in memory
            {
                int size = getSize(t); // get the size of the object, so we know how many bytes to display

                bool lEndian = isLittleEndian(); // establish whether we are on a little or big endian system
                if(!lEndian) physical = true; // in big endian, bytes are stored in the same order
                                              // as they are read (forwards) rather than the opposite (backwards)

                ulong x = Convert.ToUInt64(t); // Convert the object so that it can be evaluated numerically
                byte* ptr = (byte*)&x; // Setup a pointer to the first byte in the ulong declared above

                if(!lEndian) // if so, we are running this on a big endian system (e.g. PowerPC)
                {
                    ptr += 7;
                    ptr -= size - 1;
                }
                else if(lEndian) // if so, we are running this on a little endian system (e.g. x86/AMD64)
                {
                    if(!physical) // if so, we are not reading in consecutive order (i.e. how the bytes are stored), but rather
                    {             // in logical order (i.e. how the bytes would be displayed on screen, or stored in a register of the same size)
                        ptr += size; // This moves the pointer to the byte after the last byte in the integer
                        --ptr;      // This moves the pointer to the last byte in the integer
                    }
                }

                string r = ""; // This is the value we will use to return the hex string
                string he = "0123456789ABCDEF"; // These are all the valid hex characters

                if(physical) // If so, we are to read the bytes in the order they are stored, irrespective of endianness
                {
                    for(int i = 0; i < size; i++)
                    {
                        r += he[(*ptr) >> 4]; // Get the first nibble, add it's respective hex char on the end of the string
                        r += he[(*ptr) & 0x0F]; // do the same, but for the second (i.e. least significant) nibble
                        ++ptr; // increment the pointer, so we can read the next byte
                    }
                }

                else if(!physical) // If so, we are to read the bytes in reverse, from the last byte to the first byte in the integer
                {                  // It's worth noting that this will only ever occur on a little endian host
                    for(int i = 0; i < size; i++)
                    {
                        r += he[(*ptr) >> 4]; // Get the first nibble, add it's respective hex char on the end of the string
                        r += he[(*ptr) & 0x0F]; // do the same, but for the second (i.e. least significant) nibble
                        --ptr; // decrement the pointer, so we can read the next byte
                    }
                }

                return r; // return the hexadecimal string
            }
        }
EDIT: even more improved:

Code: Select all

unsafe static string chex(object t, bool physical)
{
    unchecked
    {
       int size = getSize(t);
 
       bool lEndian = isLittleEndian();
       physical = !lEndian ? true : physical;
 
       ulong x = Convert.ToUInt64(t);
       byte* ptr = (byte*)&x;
 
       ptr = !lEndian ? ((ptr + 7) - (size - 1)) : (!physical ? ptr + size - 1 : ptr);
 
       string r = "";
 
       for(int i = 0; i < size; i++)
       {
           r += "0123456789ABCDEF"[(*ptr) >> 4];
           r += "0123456789ABCDEF"[(*ptr) & 0x0F];
           ptr = physical ? ++ptr : --ptr;
       }
 
       return r;
    }
}
Basically, with these changes the following:
I wrote:According to my theory, I should get the following output if I was to run this under an implementation of .NET that is running on a big endian system (e.g. PowerPC-based systems):

Code: Select all

Pointer exercise using Visual C#

Here we are displaying first a ushort, then a uint then a ulong.
We display firstly the values in the order they appear when displaying them,
and then we are displaying them in the order they are stored on x86,
(i.e. little endian).

This program is endian-independant, however, so it won't matter if your
.NET implementation is running on a big endian machine.

Type: System.Byte
original: E2
reversed: E2 (this is how the integer is stored in memory)

Type: System.UInt16
original: FFAA
reversed: FFAA (this is how the integer is stored in memory)

Type: System.UInt32
original: FFA23BC4
reversed: FFA23BC4 (this is how the integer is stored in memory)

Type: System.UInt64
original: FFFFFFFFFFA23BC4
reversed: FFFFFFFFFFA23BC4 (this is how the integer is stored in memory)

Press a key to continue
but I have yet to test this theory, as I lack a PPC-based machine. I had Linux on my PS3 some time ago, and the PS3 uses a Cell processor, which irrc is based on PowerPC, but I don't have Linux on it anymore. I also can't test it now, since I installed that update that disables Linux on PS3...
Should much more likely be true (i.e. my theory should now be correct with the new code).

EDIT2:

Code: Select all

        unsafe static string chex(object t, bool physical)
        {
            unchecked
            {
                int size = getSize(t);

                bool lEndian = isLittleEndian();
                physical = !lEndian ? true : physical;

                ulong x = Convert.ToUInt64(t);
                byte* ptr = (byte*)&x;

                ptr = !lEndian ? ((ptr + (sizeof(ulong) - 1)) - (size - 1)) : (!physical ? ptr + size - 1 : ptr);

                string r = "";

                for (int i = 0; i < size; i++)
                {
                    r += "0123456789ABCDEF"[(*ptr) >> 4];
                    r += "0123456789ABCDEF"[(*ptr) & 0x0F];
                    ptr = physical ? ++ptr : --ptr;
                }

                return r;
            }
        }
lordmissus
Ignorant Child
Posts: 326
Joined: Mon Apr 06, 2009 10:10 pm
Location: 1984

Re: Ways of reversing the byte order of an unsigned integer

Post by lordmissus »

Slightly refactored for extra readability:

Code: Select all

        // Output the hex string of an unsigned type with the bytes in reversed 
        // (how the computer stores it) and logical (how a human will see it) byte order
        unsafe static string chex(object type, bool readInLiteralOrder)
        {
            unchecked
            {
                int size = getSize(type);

                ulong x = Convert.ToUInt64(type);
                byte* ptr = (byte*)&x;

                if (isLittleEndian())
                {
                    if (!readInLiteralOrder) ptr += size - 1;
                }
                else
                {
                    readInLiteralOrder = true;
                    ptr += sizeof(ulong) - 1;
                    ptr -= size - 1;
                }

                string r = "";

                for (int i = 0; i < size; i++)
                {
                    r += "0123456789ABCDEF"[(*ptr) >> 4];
                    r += "0123456789ABCDEF"[(*ptr) & 0x0F];
                    ptr = readInLiteralOrder ? ++ptr : --ptr;
                }

                return r;
            }
        }
PHoNyMiKe
Retrosexual
Posts: 1011
Joined: Wed Jul 28, 2004 2:09 am
Location: Rapture

Re: Ways of reversing the byte order of an unsigned integer

Post by PHoNyMiKe »

dude it was a cool idea but I think you killed it. it's just byte swapping, it's pretty simple. all that code you posted looks like snes9x's source code.
lordmissus
Ignorant Child
Posts: 326
Joined: Mon Apr 06, 2009 10:10 pm
Location: 1984

Re: Ways of reversing the byte order of an unsigned integer

Post by lordmissus »

Yes well byte swapping is not exactly rocket science. I can probably get my cat to understand it (no shit).
Really though, I've started using pointers in C# lately, and I've descovered other useful feature.

Just being insane really, using a bazooka to swat a fly.
You see, it's easier to test out features of a language by writing a small program that uses it, rather than starting a large project*.

Also,

Code: Select all

        unsafe static int getSize(object type) {
            if (null == type) throw new NullReferenceException(); // Fail fast, fail early

            object[] types = new object[] { (byte)0, (ushort)0, (uint)0, (ulong)0 }; // The types that are supported
            int index = 0; // This is used to index an array of sizes, corresponding to the object[] array above

            for (int i = 0; !type.GetType().IsInstanceOfType(types[index = i++]); ) // Loop until the type is verified
                if (types.Length == i)
                    throw new Exception("getSize(object) ERROR! UNSUPPORTED TYPE ''''"
                    + type.GetType() + "''''. Stop"); // Fast fast, fail early

            return (int)(new int[] { 1, sizeof(ushort), sizeof(uint), sizeof(ulong) }[index]); } // return the size

Code: Select all

        unsafe static string chex(object type, bool literal) {
            if (null == type) throw new NullReferenceException(); // fast fast, fail early

            int size = getSize(type);
            ulong x = Convert.ToUInt64(type);
            byte* ptr = getStart((byte*)&x, size, sizeof(ulong), ref literal);

            string r = "", hex = "0123456789ABCDEF"; // The strings used for the hex conversion
            for (int i = 0; i < size; i++) {
                r += hex[(*ptr) >> 4] + "" + hex[(*ptr) & 0xF];
                ptr = literal ? ++ptr : --ptr; } // if literal, read forwards,
                                                 // otherwise read backwards (little endian only)
            return (string)r; }

Code: Select all

        unsafe static byte* getStart(byte* ptr, int objSize, int containerSize, ref bool literal) {
            if (null == ptr) throw new NullReferenceException();

            return ptr + (isLittleEndian() ? // Point to the first byte in x
                (literal ? 0 : objSize - 1) : // for little endian machines
                (literal = true) ? containerSize - objSize : 0); } // for big endian machines

Code: Select all

        unsafe static byte* getStart(byte* ptr, int objSize, int containerSize, ref bool literal) {
            if (null == ptr) throw new NullReferenceException();

            return ptr + (isLittleEndian() ? // Point to the first byte in x
                (literal ? 0 : objSize - 1) : // for little endian machines
                (literal = true) ? containerSize - objSize : 0); } // for big endian machines

Code: Select all

        unsafe static bool isNegative(object type) {
            if (null == type) throw new NullReferenceException();

            ulong x = Convert.ToUInt64(type);
            bool literal = false;
            byte* ptr = getStart((byte*)&x, getSize(type), sizeof(ulong), ref literal);

            *ptr >>= 7;

            return *(bool*)ptr; }

Code: Select all

        unsafe static bool isZero(object type) // check if an unsigned integer of any size is zero, the insane batshit way
        {
            if(null == type) throw new NullReferenceException();

            bool literal = true;
            int size = getSize(type);

            ulong x = Convert.ToUInt64(type);
            byte* index = getStart((byte*)&x, size, sizeof(ulong), ref literal);
            byte* ptr = index + 1;

            for(int i = 1; i < size; i++)
                *index |= *ptr++;

            return !*(bool*)index; 
        }
(note: most of these are not related to byte-swapping, I just felt like posting them)

*like my emulator for example, which is the first ever program I wrote in C#, and is actually something I started writing in order to get use to the language, which I started writing in Decemember. More info will be available in June, when I leave college. It emulates a theoretical 8-bit CPU of my design, features a debugger, memory editor and assembler, and it is for educational use as a teaching aide in order to teach students assembly programming concepts. It is my project for the course I'm taking, but the software is mine, written by me, and only me, from scratch, though I can't release it until I complete the course because until then it is "owned" by the college, so to speak.

Yes, I am insane, how did you know? I *choose*, willingly, to write a fucking Virtual Machine for an A-Level computing course.
Post Reply