Arrays inside of structures


Sometimes when doing interop, you want to have an array embedded inside of a struct. For example, something like:

struct data
{
    int header;
    int values[10];
}

that you either used in a call to interop, or with unsafe code to deal with an existing format – something like a network packet or a disk record.

You can do this in current versions of C#, but it’s ugly. The most obvious way is:

struct Data
{
    int header;
    int value0;
    int value1;
    int value2;
    int value3;
    int value4;
    int value5;
    int value6;
    int value7;
    int value8;
    int value9;
}

But that’s a bit ungainly, though, you *can* take the address of value0 and then use pointer arithmetic to access the various “array elements”. There’s a somewhat shorter version:

[StructLayout(LayoutKind.Sequential, Size=44)]
struct data
{
    int header;
    int values;
}

Setting the size to be 44. If you want to have more than one such array or have fields after the first one, you’ll need to use LayoutKind.Explicit and put a FieldOffset attribute on every field.

In either case, you access the “array” by getting a pointer to the values field, and using pointer arithmetic.

To make this a little cleaner and less error-prone, in C# 2.0 we’ve added a fixed array syntax, allowing you to write:

struct data
{
    int header;
    fixed int values[10];
}

and getting the exact same behavior. You can then treat values as if it’s a “c-style” array, using indexing, etc.

Because the underlying implementation is still using pointers and there’s the possibility of going outside the allocated space, code generated using this feature requires using “unsafe”, and therefore requires elevated privilege to execute.

Comments (13)

  1. Matthew W. Jackson says:

    I’ve always wondered about this. In college I wrote a managed wrapper for the WinMM Mixer functions, and many of them have structs containing arrays of other structs.

    Why can’t the Marshaler automatically do this? Is there some huge show-stopping reason why this can’t be implemented? I’m able to do this with manual marshaling, but that’s prone to errors and makes the code muddy.

    I love the automatic marshaling using attributes (beats the heck out of we used to have to do it in VB6), and I’m curious as to why this functionality was left out.

  2. Sean Malloy says:

    Eric,

    you guys must have read my mind.

    I’m currently updating an old DOS app (inp/outp nightmare + global variable hell)

    Reading stream of data off of custom hardware.

    There is an attribute you can apply to arrays for interop.

    [StructLayout(LayoutKind.Sequential, Pack=1)]

    public struct Test

    {

    public ushort field1;

    [MarshalAs(UnmanagedType.ByValArray, SizeConst=10)]

    public ushort[] field2;

    }

    which effectively sets the number of elementsd in field2 to 10.

    Problem is I couldn’t get it working with structs I had declared. ala

    [StructLayout(LayoutKind.Sequential, Pack=1)]

    struct ShiftData

    {

    [MarshalAs(UnmanagedType.ByValArray, SizeConst=6)]

    public SubShift[] Shifts;

    }

    will the fixed keyword work on user defined types?

  3. Sean Malloy says:

    I just loaded up express 2005…

    It doesn’t seem to support multi dimensional arrays..

    say I have this struct:

    struct Data

    {

    int rows[2][64];

    }

    Will there be any way to apply fixed to that?

    I’ve already used a work-around. I’m just curious.

  4. Nnamdi says:

    I had the same problem when using custom types. In the end, I had to use a byte[] large enough to contain all the objects, then use Marshal.Copy.

  5. Eric,

    This example uses an array of ints. Will this new feature support complex value/reference types?

  6. Matthew W. Jackson says:

    (I think) I posted this question before, but I guess it got lost in the comment moderation problem.

    Anyway, I was wondering why the .NET Marshaler is unable to provide an automatic way to marshal structs with pointers to an array of structs.

    For a project back in college, I wrote a C# wrapper for the winmm Mixer library, and I quickly found out that I had to manually marshal several of the structs. I know that I could use pointers and avoid the problem, but I wanted to avoid unsafe code (and I’m aware that any P/Invoke code isn’t technically "safe").

    Is there a good reason why isn’t there an attribute to put on the array to allow this? Or has this been fixed in 1.1 or 2.0 and I’m just not aware of it? Is it perhaps impossible to cover every situation with marshaling attributes?

  7. pyw says:

    I want to sizeof the struct,how to?

  8. Flier Lu says:

    Ping Back来自:blog.csdn.net

  9. hello world says:

    what about this:

    [StructLayout(LayoutKind.Sequential, Pack=1/*why not 4?-i thought that was the most common for unmanaged code*/)]

    struct ShiftData

    {

    [MarshalAs(UnmanagedType.ByValArray,ArraySubType=UnmanagedTyp.LPStruct, SizeConst=6)]

    public SubShift[] Shifts;

    }

Skip to main content