StructLayout and unions

C

Chuck Bowling

I have a struct that i want to emulate a C++ style union:

[StructLayout(LayoutKind.Explicit)]
public struct Samp
{
[FieldOffset(0)] public byte[] byteBuf;
[FieldOffset(0)] public int[] intBuf;

public Samp(int sz)
{
byteBuf = new byte[sz];
intBuf = new int[sz];
}
}

To be honest, i don't really understand what's going on here. My
understanding is that an 'int' is 32 bits. A byte is 8 bits. The union of a
'int' with a byte array should only require 4 bytes. Therefore, a byte array
of 8 should be able to hold 2 ints. But, if i try the following:

[StructLayout(LayoutKind.Explicit)]
public struct Samp
{
[FieldOffset(0)] public byte[] byteBuf;
[FieldOffset(0)] public int[] intBuf;

public Samp(int sz)
{
byteBuf = new byte[sz];
intBuf = new int[sz/4]; // note smaller size
}
}

and access the byte array beyond byte[3], I get an OutOfRangeException.

Does this mean that I have to allocate 4 bytes for every byte that I
allocate in the byte array to accomodate the ints? That kind of defeats one
of the benefits of unions...
 
M

Mattias Sjögren

Chuck,

Personally I'd forget about the union, and use Buffer.BlockCopy to
copy data between a byte[] and int[]. Using explicit field offsets for
arrays like that doesn't work since the union consists of the array
references, not their data.



Mattias
 
C

Chuck Bowling

yes Sinjin, i know that...

However, if i allocate and int buffer consisting of 2 ints, i should be able
to access the byte array at byte[4] because the buffer should be 8 bytes
long.

Sijin Joseph said:
There will be no data beyond index 3, arrays in .Net are zero
based...your 4 bytes are 0,1,2,3

Sijin Joseph
http://www.indiangeek.net
http://weblogs.asp.net/sjoseph



Chuck said:
I have a struct that i want to emulate a C++ style union:

[StructLayout(LayoutKind.Explicit)]
public struct Samp
{
[FieldOffset(0)] public byte[] byteBuf;
[FieldOffset(0)] public int[] intBuf;

public Samp(int sz)
{
byteBuf = new byte[sz];
intBuf = new int[sz];
}
}

To be honest, i don't really understand what's going on here. My
understanding is that an 'int' is 32 bits. A byte is 8 bits. The union of a
'int' with a byte array should only require 4 bytes. Therefore, a byte array
of 8 should be able to hold 2 ints. But, if i try the following:

[StructLayout(LayoutKind.Explicit)]
public struct Samp
{
[FieldOffset(0)] public byte[] byteBuf;
[FieldOffset(0)] public int[] intBuf;

public Samp(int sz)
{
byteBuf = new byte[sz];
intBuf = new int[sz/4]; // note smaller size
}
}

and access the byte array beyond byte[3], I get an OutOfRangeException.

Does this mean that I have to allocate 4 bytes for every byte that I
allocate in the byte array to accomodate the ints? That kind of defeats one
of the benefits of unions...
 
C

Chuck Bowling

Thank you for the suggestion Mattias. I'm trying to read a stream into a
structure. Depending on the info in the header of the stream the data will
be either bytes, shorts, or ints. The problem is that the data can also be
packed ints 24 bits long that will need to be expanded to 32 bits. Anyway,
i'll figure it out. I'm sure that if i bang my head on the monitor hard
enough the solution will leak thru... :)
 
S

Sijin Joseph

Check out this article
http://msdn.microsoft.com/library/d...uide/html/cpcondefaultmarshalingforarrays.asp

The problem is that since Arrays are reference types at FieldOffset 0 in
ur struct there are just pointers to the actual arrays on the heap.

you need to put the MarshalAs(UnmanagedType.ByValArray) attribute on
your field declaration, but that requires the size to be fixed. I guess
you will have to use a pointer type then. Check out the custom
marshalling articles on MSDN related to the link above, they should be
of help.

Let me know if you get stuck.

Sijin Joseph
http://www.indiangeek.net
http://weblogs.asp.net/sjoseph



Chuck said:
yes Sinjin, i know that...

However, if i allocate and int buffer consisting of 2 ints, i should be able
to access the byte array at byte[4] because the buffer should be 8 bytes
long.

There will be no data beyond index 3, arrays in .Net are zero
based...your 4 bytes are 0,1,2,3

Sijin Joseph
http://www.indiangeek.net
http://weblogs.asp.net/sjoseph



Chuck said:
I have a struct that i want to emulate a C++ style union:

[StructLayout(LayoutKind.Explicit)]
public struct Samp
{
[FieldOffset(0)] public byte[] byteBuf;
[FieldOffset(0)] public int[] intBuf;

public Samp(int sz)
{
byteBuf = new byte[sz];
intBuf = new int[sz];
}
}

To be honest, i don't really understand what's going on here. My
understanding is that an 'int' is 32 bits. A byte is 8 bits. The union

of a
'int' with a byte array should only require 4 bytes. Therefore, a byte
array
of 8 should be able to hold 2 ints. But, if i try the following:

[StructLayout(LayoutKind.Explicit)]
public struct Samp
{
[FieldOffset(0)] public byte[] byteBuf;
[FieldOffset(0)] public int[] intBuf;

public Samp(int sz)
{
byteBuf = new byte[sz];
intBuf = new int[sz/4]; // note smaller size
}
}

and access the byte array beyond byte[3], I get an OutOfRangeException.

Does this mean that I have to allocate 4 bytes for every byte that I
allocate in the byte array to accomodate the ints? That kind of defeats
one
of the benefits of unions...
 
C

Chuck Bowling

Thanks for your help Sijin. I'm looking at a different approach right now. I
needed to tweak my Stream class anyhow... ;)

Sijin Joseph said:
Check out this article
http://msdn.microsoft.com/library/d...uide/html/cpcondefaultmarshalingforarrays.asp

The problem is that since Arrays are reference types at FieldOffset 0 in
ur struct there are just pointers to the actual arrays on the heap.

you need to put the MarshalAs(UnmanagedType.ByValArray) attribute on
your field declaration, but that requires the size to be fixed. I guess
you will have to use a pointer type then. Check out the custom
marshalling articles on MSDN related to the link above, they should be
of help.

Let me know if you get stuck.

Sijin Joseph
http://www.indiangeek.net
http://weblogs.asp.net/sjoseph



Chuck said:
yes Sinjin, i know that...

However, if i allocate and int buffer consisting of 2 ints, i should be able
to access the byte array at byte[4] because the buffer should be 8 bytes
long.

There will be no data beyond index 3, arrays in .Net are zero
based...your 4 bytes are 0,1,2,3

Sijin Joseph
http://www.indiangeek.net
http://weblogs.asp.net/sjoseph



Chuck Bowling wrote:

I have a struct that i want to emulate a C++ style union:

[StructLayout(LayoutKind.Explicit)]
public struct Samp
{
[FieldOffset(0)] public byte[] byteBuf;
[FieldOffset(0)] public int[] intBuf;

public Samp(int sz)
{
byteBuf = new byte[sz];
intBuf = new int[sz];
}
}

To be honest, i don't really understand what's going on here. My
understanding is that an 'int' is 32 bits. A byte is 8 bits. The union

of a
'int' with a byte array should only require 4 bytes. Therefore, a byte
array

of 8 should be able to hold 2 ints. But, if i try the following:

[StructLayout(LayoutKind.Explicit)]
public struct Samp
{
[FieldOffset(0)] public byte[] byteBuf;
[FieldOffset(0)] public int[] intBuf;

public Samp(int sz)
{
byteBuf = new byte[sz];
intBuf = new int[sz/4]; // note smaller size
}
}

and access the byte array beyond byte[3], I get an OutOfRangeException.

Does this mean that I have to allocate 4 bytes for every byte that I
allocate in the byte array to accomodate the ints? That kind of defeats
one

of the benefits of unions...
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top