Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Properly copy C# structs with (byte) arrays in them?

From what I understand, when assigning a struct variable to another one, the first one is usually copied instead of creating a reference:

public struct MYSTRUCT1
{
    public byte val1;
}
// (...)
public DoSomething() {
    MYSTRUCT1 test1;
    test1.val1 = 1;
    MYSTRUCT1 test2 = test1;
    test2.val1 = 2;

    Console.WriteLine(test1.val1);
    Console.WriteLine(test2.val1);
}

This works just fine, the output is:

1
2

However, if I have a byte[] inside my struct, this behaviour changes:

public struct MYSTRUCT1
{
    public byte[] val1;
}
// (...)
public DoSomething() {
    MYSTRUCT1 test1;
    test1.val1 = new byte[0x100];
    test1.val1[0] = 1;
    MYSTRUCT1 test2 = test1;
    test2.val1[0] = 2;

    Console.WriteLine(test1.val1[0]);
    Console.WriteLine(test2.val1[0]);
}

This is the output:

2
2

How can I avoid this? I really need to work with a copy of the complete struct including any byte arrays.

Thank you! ♪


Edit: Thanks for all your help! In order to deep copy my struct, I’m now using this code:

public static object deepCopyStruct(object anything, Type anyType)
{
    return RawDeserialize(RawSerialize(anything), 0, anyType);
}

/* Source: http://bytes.com/topic/c-sharp/answers/249770-byte-structure */
public static object RawDeserialize(byte[] rawData, int position, Type anyType)
{
    int rawsize = Marshal.SizeOf(anyType);
    if (rawsize > rawData.Length)
        return null;
    IntPtr buffer = Marshal.AllocHGlobal(rawsize);
    Marshal.Copy(rawData, position, buffer, rawsize);
    object retobj = Marshal.PtrToStructure(buffer, anyType);
    Marshal.FreeHGlobal(buffer);
    return retobj;
}

/* Source: http://bytes.com/topic/c-sharp/answers/249770-byte-structure */
public static byte[] RawSerialize(object anything)
{
    int rawSize = Marshal.SizeOf(anything);
    IntPtr buffer = Marshal.AllocHGlobal(rawSize);
    Marshal.StructureToPtr(anything, buffer, false);
    byte[] rawDatas = new byte[rawSize];
    Marshal.Copy(buffer, rawDatas, 0, rawSize);
    Marshal.FreeHGlobal(buffer);
    return rawDatas;
}

It must be called like this:

MYSTRUCT1 test2 = (MYSTRUCT1)deepCopyStruct(test1, typeof(MYSTRUCT1));

This seems to work fine, though I’m aware that this is dirty code.

However, since the structs I’m working with have over 50 byte[] several other structs in them, it’s just too much work to write Copy()/Clone() methods for each of them.

Suggestions for better code are of course very welcome.

like image 811
Buoysel Avatar asked Aug 21 '10 12:08

Buoysel


People also ask

Is there a copy function in C?

C strcpy() The strcpy() function copies the string pointed by source (including the null character) to the destination. The strcpy() function also returns the copied string.

How does strcpy work in C?

The strcpy() function copies string2, including the ending null character, to the location that is specified by string1. The strcpy() function operates on null-ended strings. The string arguments to the function should contain a null character (\0) that marks the end of the string. No length checking is performed.

How do you copy a Cstring?

You could use strdup() to return a copy of a C-string, as in: #include <string. h> const char *stringA = "foo"; char *stringB = NULL; stringB = strdup(stringA); /* ... */ free(stringB);

Does strcpy overwrite?

The strcpy() function does not stop until it sees a zero (a number zero, '<0') in the source string. Since the source string is longer than 12 bytes, strcpy() will overwrite some portion of the stack above the buffer.


1 Answers

You will have to create a Clone method to do a deep copy of the struct's members:

public struct MyStruct
{
    public byte[] data;
    public MyStruct Clone()
    {
        byte[] clonedData = new byte[this.data.Length];
        data.CopyTo(clonedData, 0);

        return new MyStruct { data = clonedData };
    }
}
like image 150
Lee Avatar answered Sep 21 '22 01:09

Lee