C# equivalent to C "union"?

Is there a C# equivalent to the C union typedef? I have a 64 byte array that can either be byte or int (USB data packet). I would like to be able to access these bytes as either type. In C I would declare:

typedef union byte_array
{
struct{byte byte1;byte byte2;byte byte3;byte byte4;};
struct{int int1;int int2;};
};byte_array


...and access them by:

byte_array myarray;
mybyte = myarray.byte1;
myint = myarray.int1;

How would I accomplish this in C#?
[1123 byte] By [mihooper] at [2007-12-17]
# 1
There is no union in C#. Other options are necessary, such as unsafe code, or a class like this

public class U {

short s;

//==================================================

public U(short s) {

this.s = s;

}

//==================================================

public byte AsByte(byte index) {

const short maskLeft = 0xF0;

const short maskRight = 0x0F;

switch (index) { // index: 0..3

case 0:

return (byte)((maskLeft & s) >> 4); // shift right 4 bits

case 1:

return (byte)(maskRight & s);

default:

return 0;

}

}

}



where the access code is written to favor bytes or shorts, whichever values are the most common. sorry about the code format

PeterNRoth at 2007-9-8 > top of Msdn Tech,Visual C#,Visual C# Language...
# 2
C# doesn't natively support the C/C++ notion of unions. You can however use the StructLayout(LayoutKind.Explicit) and FieldOffset attributes to create equivalent functionality. I'll assume that you meant a 64-bit data structure, which would contain 8 bytes or 2 ints. If you really did mean a 64-byte data structure, you would need to define a struct with 64 bytes and 16 ints. (Probably better to use a byte[] and a int[].) You can find information here:

http://winfx.msdn.microsoft.com/library/default.asp?url=/library/en-us/dv_csref/html/163ab9b5-46f6-4d78-9025-f7bbba89b2e1.asp

For instance:

using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Explicit)]
struct ByteArray {
[FieldOffset(0)]
public byte Byte1;
[FieldOffset(1)]
public byte Byte2;
[FieldOffset(2)]
public byte Byte3;
[FieldOffset(3)]
public byte Byte4;
[FieldOffset(4)]
public byte Byte5;
[FieldOffset(5)]
public byte Byte6;
[FieldOffset(6)]
public byte Byte7;
[FieldOffset(7)]
public byte Byte8;
[FieldOffset(0)]
public int Int1;
[FieldOffset(4)]
public int Int2;
}

One thing to be careful of is the endian-ness of the machine if you plan to run it on non-x86 platforms that may have differing endianness. See http://en.wikipedia.org/wiki/Endianness for an explanation.

JamesKovacs at 2007-9-8 > top of Msdn Tech,Visual C#,Visual C# Language...
# 3

You can actually do the following:


using System;
using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Explicit)]
struct byte_array
{
[FieldOffset(0)]
public byte byte1;

[FieldOffset(1)]
public byte byte2;

[FieldOffset(2)]
public byte byte3;

[FieldOffset(3)]
public byte byte4;

[FieldOffset(0)]
public short int1;

[FieldOffset(2)]
public short int2;
}


However, you need to be careful as the 'int' datatype in the .NET Framework is actually a 32-bit integer not 16-bit. So 2 bytes actually make up 1 short.

DavidM.Kean at 2007-9-8 > top of Msdn Tech,Visual C#,Visual C# Language...
# 4
+1, David. We obviously posted our solution at the same time. :)
JamesKovacs at 2007-9-8 > top of Msdn Tech,Visual C#,Visual C# Language...
# 5
James,

Great minds think a like. Looks like we posted the same answer at the same time. ;)

DavidM.Kean at 2007-9-8 > top of Msdn Tech,Visual C#,Visual C# Language...
# 6
James,

You may want to fix up FieldOffset for the Int2 field in your struct. It should be changed from 1 to 4.

DavidM.Kean at 2007-9-8 > top of Msdn Tech,Visual C#,Visual C# Language...
# 7
Good catch, David. I was thinking it was the second int and therefore position 1, but the field numbering is based on the bytes. Serves me right for not dropping it into VS or Snippet Compiler and verifygin it before posting. Thanks!
JamesKovacs at 2007-9-8 > top of Msdn Tech,Visual C#,Visual C# Language...
# 8
Peter, David, James,

Thanks for the help!

So, to reference the "int1" above, would I do the following?


myint = byte_array.int1

I will modify the structure for "short" instead of "int" since the other end of the USB link thinks ints are 16 bits...;)

Thanks again!

mihooper at 2007-9-8 > top of Msdn Tech,Visual C#,Visual C# Language...
# 9
Yep that's right.

Cheers

David

DavidM.Kean at 2007-9-8 > top of Msdn Tech,Visual C#,Visual C# Language...
# 10
David & James - if the data didnt have to 'match' the layout as presented by a C program, say, what would you recommend for storage of these data?
PeterNRoth at 2007-9-8 > top of Msdn Tech,Visual C#,Visual C# Language...
# 11
It would honestly depend on a variety of other factors. If I could detect the type of the incoming data, I would create two different structs and let the CLR lay them out optimally based on the underlying platform (x86, IA64, x64, etc.). Then I could select whichever data structure I needed at runtime. I might also consider an abstract base class with common methods and then two concrete classes that contain the data. Yet another option would be a generic type with element type specified as a template parameter. Lots of options and the best option depends on the problem at hand.
JamesKovacs at 2007-9-8 > top of Msdn Tech,Visual C#,Visual C# Language...