Workaround for declaring an unsafe fixed custom array?

Is there a workaround for error CS1663 ("A fixed buffer type must be one of the following: bool, byte, short, int, long, char, sbyte, ushort, uint, ulong, float or double.")?

I need to declare an unsafe fixed array from another branch structure, but I am stuck with this compiler error.

Display code to find out the problem below.

struct s1 { byte _b1; byte _b2; } unsafe struct s2 { fixed s1 _s1[5]; // CS1663 here... } 

Please note that the two structures are blittable, so the error does not make any sense to me.

Does anyone know what I can do?

Thanks.

+5
source share
3 answers

This is a limitation of fixed size buffers .

A fixed array can accept any attributes or modifiers that are allowed for regular members of the structure. The only limitation is that the array type must be bool , byte , char , short , int , long , sbyte , ushort , uint , ulong , float or double .

You can use only those types, but not a combination (for example, a struct contains only those types). It makes no difference if your type is bittable or not. You just can't use it.

Then you cannot use your own struct for a fixed size buffer.

Workaround? Mmmm, yes, maybe. You can change the structure of the code and use something like this:

 unsafe struct s2 { fixed byte _b1[5]; fixed byte _b2[5]; } 
+1
source

Another way is to use fields like pointer.

 public struct Foo { public byte _b1; public byte _b2; } public unsafe struct Bar { public int Length; public unsafe Foo* Data; } 

On the other hand, if you intended to create a single object of type value that would contain all your own data continuously (i.e. it could be memcpy'd in unmanaged code) - then the only way to do this is to not use arrays at all.

 public struct Foo { public byte _b1; public byte _b2; } public struct Bar1 { public Foo F1; } public struct Bar2 { public Foo F1; public Foo F2; } public struct Bar3 { public Foo F1; public Foo F2; public Foo F3; } 
0
source

How would I approach your example and similar ones in complexity, I would first ask myself if the structure can be reduced to one primitive type. If possible, I would simply hide the fixed buffer inside the structure through access to the property or indexer.

In your example, you had the following.

 struct s1 { byte _b1; byte _b2; } unsafe struct s2 { fixed s1 _s1[5]; // CS1663 here... } 

What I could consider if I decided that I absolutely needed structures to be combined into one continuous data block is something like this.

 [StructLayout(LayoutKind.Explicit, Size = 2)] struct s1 { // Field offsets to emulate union style access which makes it // simple to get at the raw data in a primitive type format. [FieldOffset(0)]ushort _u1; [FieldOffset(0)]byte _b1; [FieldOffset(1)]byte _b2; public s1(ushort data) { _b1 = 0; _b2 = 0; _u1 = data; } public ushort ToUShort() { return _u1; } } unsafe struct s2 { public const int Size = 5; private fixed ushort _s1[Size]; public s1 this[int index] { // A public indexer that provides the data in a friendlier format. get { if (index < 0 || index >= Size ) throw new IndexOutOfRangeException(); return new s1(_s1[index]); } set { if (index < 0 || index >= Size) throw new IndexOutOfRangeException(); _s1[index] = value.ToUShort(); } } } 

If it looks like a hack, then because it's kind of like. I would not recommend this as a general solution, because it is difficult to maintain, but in those rare cases when you work at such a low level and know in advance that the data specification will not change, then something like this method may be viable. But even in these cases, I would still prefer to encapsulate as much as possible of such a low level to minimize the likelihood that something will go wrong. However, this does exactly as required, for a workaround to having a fixed buffer size of user structures.

0
source

Source: https://habr.com/ru/post/1246911/


All Articles