1

How do I initialize an array of structs within a struct in C#?

public const int MAX_AXIS = 10;

struct realprm
{     /* real parameter */
    long prm_val;             /* value of variable */
    long dec_val;             /* number of places of decimals */
};

[StructLayout(LayoutKind.Explicit)]
unsafe struct iodbpsd
{
    [FieldOffset(0)] short datano;               /* parameter number */
    [FieldOffset(2)] short type;                 /* upper byte:type */
    
    /* lower byte:axis */{
    [FieldOffset(4)] char cdata;           /* bit/byte parameter */
    [FieldOffset(4)] short idata;           /* word parameter */
    [FieldOffset(4)] long ldata;           /* 2-word parameter */
    [FieldOffset(4)] realprm rdata;           /* real parameter */
    [FieldOffset(4)] fixed char cdatas[MAX_AXIS];/*bit/byte parameter with axis*/
    [FieldOffset(4)] fixed short idatas[MAX_AXIS];/* word parameter with axis */
    [FieldOffset(4)] fixed long ldatas[MAX_AXIS];/* 2-word parameter with axis */
    [FieldOffset(4)] realprm rdatas[MAX_AXIS];/* real parameter with axis */
};

The last entry, realprm, throws compiler errors:

CS0270 Array size cannot be specified in a variable declaration (try initializing with a 'new' expression)

CS0650 Bad array declarator: To declare a managed array the rank specifier precedes the variable's identifier. To declare a fixed size buffer field, use the fixed keyword before the field type.

The 'fixed' keyword won't work for structs, and C# does not allow 'new' keyword initialization:

CS0573 Field declaration: cannot have instance field initializers in structs

Is there any elegant way to initialize an array like this in C#?

2
  • 2
    Try defining as fixed byte rdatas[MAX_AXIS * sizeof(realprm)], accessing to such array elements can be done via helper methods. Commented Jun 18 at 17:28
  • I will give it a shot. Commented Jun 19 at 16:55

3 Answers 3

2

From the language specification, section 23.8.2 Fixed-size buffer declarations:

The buffer element type shall be one of the predefined types sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, or bool.

Hence you can't define a fixed array of custom structs.

You can look into using the inline arrays added with C# 12:

[System.Runtime.CompilerServices.InlineArray(MAX_AXIS)]
public struct BufferMAX_AXIS<TT>
{
    private TT _element0;
}

And then use it in your type, but this depends on what actually is needed.

Also it is a bit strange that there is a lot of fields starting on the same offset (i.e. [FieldOffset(4)]).

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you. I am trying to communicate with industrial equipment, and depending on the data to be retrieved, it will be of different lengths, but all starting at the offset +4, hence the multiple items at 4.
1

You can create a new instance of an array within a constructor. Try the following:

public const int MAX_AXIS = 10;

struct RealPrm
{
    long prmVal;
    long decVal;
}

[StructLayout(LayoutKind.Explicit)]
unsafe struct IoDbPsd
{
    [FieldOffset(0)] short dataNo;
    [FieldOffset(2)] short type;
    [FieldOffset(4)] char cData;
    [FieldOffset(4)] long lData;
    [FieldOffset(4)] RealPrm rData;
    [FieldOffset(4)] fixed char cDatas[MAX_AXIS];
    [FieldOffset(4)] fixed short iDatas[MAX_AXIS];
    [FieldOffset(4)] fixed long lDatas[MAX_AXIS];
    [FieldOffset(4)] RealPrm[] rDatas;

    public IoDbPsd()
    {
        rDatas = new RealPrm[MAX_AXIS];
    }
}

Resources:

1 Comment

This was helpful. Apparently you can't use objects or structs in a de facto C# struct union. If I remove the RealPrm members, the data sitting at +4 will play nicely.
0
    public class IODBPSD_3
    {
        [FieldOffset(0)]
        public short datano;    /* data number */
        [FieldOffset(2)]
        public short type;      /* axis number */
        [FieldOffset(4),
        MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_AXIS)]
        public byte[] cdatas = new byte[MAX_AXIS];
        [FieldOffset(4),
        MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_AXIS)]
        public short[] idatas = new short[MAX_AXIS];
        [FieldOffset(4),
        MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_AXIS)]
        public int[] ldatas = new int[MAX_AXIS];
    }

The equipment manufacturer had this buried in their code.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.