0

I have a register which reads out the version number in the following format. It is little endian. For example:

The register value read is 0x15000000 but I need to represent this in the GUI as 00.00.00_15.

How do I print in particular format with taking care of reversal as well in C#?

Ben Reich
  • 16,222
  • 2
  • 38
  • 59

3 Answers3

5

You could use the BitConverter.GetBytes to get an array of bytes..

int num = 0x15000000;
var bytes = BitConverter.GetBytes(num);

// If you want your code to run even on your Big Endian fridge,
// decomment this line :)
// if (!BitConverter.IsLittleEndian) Array.Reverse(bytes);

string str = string.Format("{0:x2}.{1:x2}.{2:x2}_{3:x2}", bytes[0], bytes[1], bytes[2], bytes[3]);

and then string.Format("{num:x2}" where x2 will give an hex format of 2 digits

Note that in general, the BitConverter.GetBytes should be used only on Intel/AMD computers! If you want to make a generic code that can run anywhere, including your fridge, then it's better to use the next solution! (because your fridge could be Big Endian!)

Clearly you could do bit manipulation, shift >> and &

string str = string.Format("{0:x2}.{1:x2}.{2:x2}_{3:x2}", num & 0xFF, (num >> 8) & 0xFF, (num >> 16) & 0xFF, (num >> 24) & 0xFF);

But it's quite unreadable, unless you know a little of bit-manipulation :)

xanatos
  • 109,618
  • 12
  • 197
  • 280
  • "The order of bytes in the array returned by the GetBytes method depends on whether the computer architecture is little-endian or big-endian." https://msdn.microsoft.com/en-us/library/de8fssa4(v=vs.110).aspx – weston Mar 16 '15 at 12:57
  • So I think you should take a look at the [`IsLittleEndian`](https://msdn.microsoft.com/en-us/library/system.bitconverter.islittleendian(v=vs.110).aspx) static. – weston Mar 16 '15 at 12:59
  • @weston So he mustn't use it on XBox360 :-) I think it is the only big endian .NET platform – xanatos Mar 16 '15 at 12:59
  • @weston But you are right... I'll post the correction – xanatos Mar 16 '15 at 13:00
  • @xanatos What about ARM? :) It's even official part of the MS.NET (Windows Phone), not just the standardised CLR. – Luaan Mar 16 '15 at 13:01
  • Some monos and dotgnu are also big-endian according to: http://stackoverflow.com/questions/3685624/which-net-compatible-architectures-are-not-little-endian – weston Mar 16 '15 at 13:02
  • @Luaan I think that Windows Phones are always Little Endian (ARM can work in both ways)... If anyone can correct me... There is at least a reference here https://social.msdn.microsoft.com/Forums/en-US/04c92ef9-e38e-415f-8958-ec9f7c196fd3/arm-endianess-under-windows-mobile?forum=windowsmobiledev that it is so. – xanatos Mar 16 '15 at 13:03
  • @xanatos Maybe. But the CLR is still defined to operate on both little-endian and big-endian. You shouldn't write code that relies on the platform being little-endian, because you don't have any such guarantees. *This is how you get portability issues*. Just to save a line of code. – Luaan Mar 16 '15 at 13:04
  • It's a simple fix to ensure total compatibility. Shorter than the disclaimer you added. I've added code. It reads nice too. OP wants little endian order, if it is not, then it is reversed before the format. – weston Mar 16 '15 at 13:04
  • @Luaan In a perfect world, where everyone writes perfect code, you are right... And I do think you are right, because I'm a perfectionist. But, for example, those two lines of code are two more lines of code that won't probably ever be used but that will need unit testing if you want to have very high code coverage... And that unit testing will be quite difficult to do :-) There is always a tradeoff. – xanatos Mar 16 '15 at 13:08
  • @xanatos Well, yeah. That's why I'm suggesting not using `int` for storage of a value like this in the first place - there is no reason to treat a sequence of bytes as an `int` just because it's four bytes long. Even if you did need to store it in 4B square, it's a better idea to use a custom `struct`, for example, or abstract away the `int`. But it's hard to get anywhere before the OP gets back with more information :) – Luaan Mar 16 '15 at 13:11
2

Don't treat it as a number - it's not a number. The fact that you can efficiently store it as a single int is irrelevant - just an implementation detail.

Once you start thinking in bytes in an array, you find that "little-endian" is not really anything important. Instead, you just have a structure that starts with one byte meaning one thing, the next one something else...

There's many ways to get to that behaviour, depending on where you get the actual value - taking an int will not give you control over endianness, for example. If you just take a byte[], you can do something like this:

string.Format("{0}.{1}.{2}_{3}", data[3], data[2], data[1], data[0])

This is usually very easy to handle when you're working with e.g. loading data from a file, or sending it over a socket. If you're dealing with native code interop, you can use a structure instead of int (or similar):

struct MyVersionNumber
{
  byte Lowest;
  byte Other;
  byte YetAnother;
  byte Highest;
}

Think in types - don't use primitives unless what you have is a primitive value. You're obviously working with a composite value that's (for whatever reason) folded into a primitive type. That's not a good idea for maintaining complexity :)

Once you have type, you can ensure proper type safety, validation, and just override the ToString method, for example, to output the value for the user.

Luaan
  • 62,244
  • 7
  • 97
  • 116
1

Most but not all .net platforms are little endian. Therefore the correct usage of BitConverter.GetBytes is to not assume it will return one or the other.

int num = 0x15000000;
var bytes = BitConverter.GetBytes(num);
if (!BitConverter.IsLittleEndian) Array.Reverse(bytes); //it's big-endian, so reverse the bytes
string str = string.Format("{0:x2}.{1:x2}.{2:x2}_{3:x2}", bytes[0], bytes[1], bytes[2], bytes[3]);
Community
  • 1
  • 1
weston
  • 54,145
  • 21
  • 145
  • 203