How does the GetBytes function work?
Asked Answered
P

1

13

I wrote my own class which converts C# standard primitives into byte arrays.

Later on, I took a look at the BitConverter class source, to see how pros did it.

My code example:

public static byte[] getBytes(short value) {
    byte[] bytes = new byte[2];

    bytes[0] = (byte)(value >> 8);
    bytes[1] = (byte)value;

    return bytes;
}

BitConverter class code:

public unsafe static byte[] GetBytes(short value) 
{ 
    byte[] bytes = new byte[2];
    fixed(byte* b = bytes) 
        *((short*)b) = value;
    return bytes;
}

Why are their functions tagged as unsafe and use fixed operator?

Are such functions error prone even if they use unsafe? Should I just drop mine and use their implementation? Which is more efficient?

Pressurecook answered 15/8, 2015 at 11:17 Comment(1)
These functions do different things: The former uses big endian, the latter native endian.Salo
L
12

Yes, drop yours and use the standard library.

It is more efficient, because it copies both bytes at once by casting the byte array to a short pointer. To do this it requires fixed to allow the use of pointers, and hence the unsafe keyword.

Unsafe code is generally to be avoided in your own assemblies, as it means your code cannot be guaranteed safe, and so can only be run in fully trusted environments.

However, since Bitconverter is part of the standard .Net assemblies that are signed by Microsoft, Windows knows they are ok.

Library functions are less error prone too, because they have been battle hardened by millions of developers using them every day, whereas your function has been tested only by you.

Lotze answered 15/8, 2015 at 11:31 Comment(10)
Makes sense, i guess i should only create wrappers around BitConverter class, such as GetBytes from string.Pressurecook
@Pressurecook For String you should use System.Text.Encoding.GetBytes ( msdn.microsoft.com/en-us/library/… ) , not BitConverter.Puerile
You are right, i guess i should cut the "reinvent the wheel" thing.Pressurecook
It's not necessarily bad to reinvent the wheel for educational purposes, as long as you're aware that there's something better and tested out there already (and thus you remember to use that for any "serious" purposes).Trulatrull
The integer conversion functions in BitConverter are very rarely useful. If you parse files, or write communication protocols its use of native endianness causes a platform dependence. When acting on native data structure you typically have better choices available, such as the marshaller or defining a struct and casting the pointer. An top of that it's slow.Salo
Fixing the pointer is extremely slow (it pins the object). It is by no means efficient. The binary reader/writer classes put every byte in a byte array just like the OP's method: referencesource.microsoft.com/#mscorlib/system/io/…Moises
"However, since Bitconverter is part of the standard .Net assemblies that are signed by Microsoft, Windows knows they are ok" At least until the next patch Tuesday.Caller
@Moises Im interested in most efficient method. Could you please elaborate what you mean by 'Fixing the pointer is extremely slow (it pins the object)'.Pressurecook
@Pressurecook For your pointer to the array to be valid, the object must remain in the same position in memory. The .NET garbage collector normally moves objects around to optimize its use of memory, but moving an object whose pointer you're using will invalidate that pointer and cause some serious errors. Thus, the GC needs to be told not to move the object. For primitive types, your way is the most efficient. For structs, I've got a much more efficient way: s.vercas.com/cerpq (it's in this commit). You ought to fix it when it's on the stack and not on the heap to get a major speed boost.Moises
@Pressurecook You can easily do some benchmarks to test you way against the BitConverter's. The differences in performance should be significant, even when you use larger types such as long or double.Moises

© 2022 - 2024 — McMap. All rights reserved.