Question

I've found that the implementation of the GetBytes function in .net framework is something like:

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

I'm not so sure I understand the full details of these two lines:

   fixed(byte* b = bytes)
     *((int*)b) = value;

Could someone provide a more detailed explanation here? And how should I implement this function in standard C++?

Was it helpful?

Solution

Could someone provide a more detailed explanation here?

The MSDN documentation for fixed comes with numerous examples and explanation -- if that's not sufficient, then you'll need to clarify which specific part you don't understand.


And how should I implement this function in standard C++?

#include <cstring>
#include <vector>

std::vector<unsigned char> GetBytes(int value)
{
    std::vector<unsigned char> bytes(sizeof(int));
    std::memcpy(&bytes[0], &value, sizeof(int));
    return bytes;
}

OTHER TIPS

Fixed tells the garbage collector not to move a managed type so that you can access that type with standard pointers.

In C++, if you're not using C++/CLI (i.e. not using .NET) then you can just use a byte-sized pointer (char) and loop through the bytes in whatever you're trying to convert.

Just be aware of endianness...

First fixed has to be used because we want to assign a pointer to a managed variable:

The fixed statement prevents the garbage collector from relocating a movable variable. The fixed statement is only permitted in an unsafe context. Fixed can also be used to create fixed size buffers.

The fixed statement sets a pointer to a managed variable and "pins" that variable during the execution of the statement. Without fixed, pointers to movable managed variables would be of little use since garbage collection could relocate the variables unpredictably. The C# compiler only lets you assign a pointer to a managed variable in a fixed statement. Ref.

Then we declare a pointer to byte and assign to the start of the byte array.

Then, we cast the pointer to byte to a pointer to int, dereference it and assign it to the int passed in.

The function creates a byte array that contains the same binary data as your platform's representation of the integer value. In C++, this can be achieved (for any type really) like so:

int value; // or any type!
unsigned char b[sizeof(int)];
unsigned char const * const p = reinterpret_cast<unsigned char const *>(&value);
std::copy(p, p + sizeof(int), b);

Now b is an array of as many bytes as the size of the type int (or whichever type you used).

In C# you need to say fixed to obtain a raw pointer, since usually you do not have raw pointers in C# on account of objects not having a fixed location in memory -- the garbage collector can move them around at any time. fixed prevents this and fixes the object in place so a raw pointer can make sense.

You can implement GetBytes() for any POD type with a simple function template.

#include <vector>

template <typename T>
std::vector<unsigned char> GetBytes(T value)
{
    return std::vector<unsigned char>(reinterpret_cast<unsigned char*>(&value),
                                      reinterpret_cast<unsigned char*>(&value) + sizeof(value));
}

Here is a C++ header-only library that may be of help.

BitConverter

The idea of implementing the GetBytes function in C++ is straight-forward: compute each byte of the value according to specified layout. For example, let's say we need to get the bytes of an unsigned 16-bit integer in big endian. We can divide the value by 256 to get the first byte, and take the remainder as the second byte.

For floating-point numbers, the algorithm is a little bit more complicated. We need to get the sign, exponent, and mantissa of the number, and encode them as bytes. See https://en.wikipedia.org/wiki/Double-precision_floating-point_format

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top