1

I need to convert a struct to bytes so that I can send or receive it over a network.

Let's say the struct is something like below:

struct Info
{
    unsigned int Age;
    char Name[];
};

I have the equivalent struct in C# sharp which is:

[StructLayout(LayoutKind.Sequential)]
public struct Info
{
    public uint Age;
    public string Name;
};

To convert the C# struct to byte I use the this method:

    public Byte[] GetBytes(Info info)
    {
        int size = Marshal.SizeOf(info);
        byte[] arr = new byte[size];
        IntPtr ptr = Marshal.AllocHGlobal(size);

        Marshal.StructureToPtr(info, ptr, true);
        Marshal.Copy(ptr, arr, 0, size);
        Marshal.FreeHGlobal(ptr);

        return arr;
    }

And to Convert the received bytes to C++ struct I use this method:

Info GetInfo(const char* bytes)
{
    Info info;
    memcpy(&info, bytes, sizeof(info));

    return info;
}

My problem is that the Age field of the struct converts very well but the Name field never is what has been sent.

Update

I can easily convert a string to bytes using the code below and send it from c# client app to c++ server app.

        byte[] buffer = Encoding.UTF8.GetBytes(text + "\0");

so I decided to change the C# struct as below:

[StructLayout(LayoutKind.Sequential)]
public struct Info
{
    public uint Age;
    public byte[] Name;
};

but in this case the GetBytes() method crashes.

14
  • 1
    Could you offer some information on why you need a struct but moreover why you need to convert it to bytes? Commented Dec 17, 2014 at 20:53
  • A bit difficult; can you see what's transmitted "on the wire"? Commented Dec 17, 2014 at 20:54
  • 4
    If age works but name does not perhaps you are dealing with some sort of character set encoding mismatch. Commented Dec 17, 2014 at 20:55
  • 1
    The C++ code isn't using CMsg. I'm confused. In any case, the size of the struct in C++ is implementation defined, I believe (in particular because you're using the "C struct hack"). The name is of a variable length. In C#, string members are just references to the actual strings allocated on the heap, so you'll have to do a lot more legwork than merely copying the struct's bytes, but also those of the string. Commented Dec 17, 2014 at 20:58
  • 1
    It never works right to convert whole structure. You have to do it field-by-field. On c# side you're most likely getting string size as well as string content, while on C++ side there is no length. Plus, on C# side string are Unicode, 16bit per char, while on C++ side they are just chars. I would recommend to use canned solution like kentonv.github.io/capnproto Commented Dec 17, 2014 at 21:01

2 Answers 2

4
  1. Your C++-structure uses a flexible array member as the last element, which is an extension borrowed from C99:

    In essence, it means that an array of unknown length ends it.
    Because the length is not known, the compiler will, when asked for the structures size, assume 0.
    I somehow doubt that's what you wanted.

  2. Your C#-structure has a string-member, which is not a value-type.

    Just copying the managed pointer to it like you do is quite nonsensical.

So, what should you do?

Define your own wire-format.

  • An unsigned 32-bit integer will be easily marshalled.
  • The string is more difficult. Do you have a sentinel-value never part of the string?
    Or do you have to use / prefer counted strings, in which case you have to decide what type the size will be and marshal that first?

    Also, don't forget the character-set: Prefer UTF-8, though if it's windows-only, UTF-16 little-endian may also be a viable choice.

Sign up to request clarification or add additional context in comments.

2 Comments

Your explanation was really helpful and now I know what the problem is, yet I haven't figure it out what to do with it? Could you be a little more helpful on this?
Alan just posted two libraries specializing in such.
1

This can get very complicated very quickly.

You might want to look at some libraries that can help - Google Protobuf and Apache Thrift immediately spring to mind. Both support C++ and C# amongst other languages.

1 Comment

Thank you. I will test it and let you know the result.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.