Shahrooz Kia
Shahrooz Kia

Reputation: 89

C# structure include byte array and long value

This is My Code to user a long variable with it bytes, but when program runs, Exception Happens and show these:

An unhandled exception of type 'System.TypeLoadException' occurred in Test.exe

Additional information: Could not load type 'Test.MyU32' from assembly 'Test, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' because it contains an object field at offset 0 that is incorrectly aligned or overlapped by a non-object field.

[StructLayout(LayoutKind.Explicit)]
public struct MyU32
{
    [FieldOffset(0)]
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
    public byte[] Bytes;
    [FieldOffset(0)]
    public long Value;
}

Please help me how to handle it!

Upvotes: 0

Views: 753

Answers (3)

Shahrooz Kia
Shahrooz Kia

Reputation: 89

I solve my problem

Tanx to All bodies that put time on it.

public struct MyU32
{
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
    public byte[] Bytes;
    public uint Value
    {
        get { return ((uint)Bytes[0] + Bytes[1] << 8 + Bytes[2] << 16 + Bytes[3] << 24); }
        set 
        { 
            Bytes[0] = (byte)(value & 0xFF);
            Bytes[1] = (byte)(value>>8 & 0xFF);
            Bytes[2] = (byte)(value>>16 & 0xFF);
            Bytes[3] = (byte)(value>>24 & 0xFF);
        }
    }
}

Upvotes: 0

CodesInChaos
CodesInChaos

Reputation: 108830

Your code case doesn't work because you're overlapping a reference and a value type(a 64 bit int). You can overlap different value types and different references, but you can't mix them.

But even when they work, such low level hacks are usually a bad idea in C#. I recommend using properties which do the transformation instead of low level unions.

Perhaps what you actually want is:

internal static class ByteIntegerConverter
{
    public static UInt32 LoadLittleEndian32(byte[] buf, int offset)
    {
        return
            (UInt32)(buf[offset + 0])
        | (((UInt32)(buf[offset + 1])) << 8)
        | (((UInt32)(buf[offset + 2])) << 16)
        | (((UInt32)(buf[offset + 3])) << 24);
    }

    public static void StoreLittleEndian32(byte[] buf, int offset, UInt32 value)
    {
        buf[offset + 0] = (byte)value;
        buf[offset + 1] = (byte)(value >> 8);
        buf[offset + 2] = (byte)(value >> 16);
        buf[offset + 3] = (byte)(value >> 24);
    }
}

UInt32 value = ByteIntegerConverter.LoadLittleEndian32(buf, offset);
// do something with `value`
ByteIntegerConverter.StoreLittleEndian32(buf, offset, value);

This always uses little endian regardless of the computer's native endianness. If you want native endainness you could check with BitConverter.IsLittleEndian and use different shift constants if it is big endian.

Upvotes: 1

C&#233;dric Bignon
C&#233;dric Bignon

Reputation: 13022

I'm not perfectly sure, but I think the problem is caused by the overlap between a value type and a reference type. It should be possible to overlap only value types. Because if it was possible to overlap value types & reference types, you could change the reference directly. For obvious safety reason, it's not possible.

As byte[] is a reference type (as all arrays in .NET). You can't have Value overlapping Bytes.

If you are used to C, your structure (without the explicit layout) would be "similar" to:

struct MyU32
{
    byte* Bytes;
    long Value;
}

but it is not similar to:

struct MyU32
{
    byte Bytes[4];
    long Value;
}

Upvotes: 0

Related Questions