This is my struct in C:
typedef struct s1 {
int i;
union {
s2 u1;
s3 u2;
}
}
typedef struct s2
{
int w[10];
}
typedef struct s3
{
int w[10];
}
This is my code in C#:
public struct s2
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
int[] w;
}
public struct s3
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
int[] w;
}
[StructLayout(LayoutKind.Explicit)]
public struct s4
{
[FieldOffset(0)]
int i;
[FieldOffset(4)]
s2 s2;
[FieldOffset(4)]
s3 s3;
}
When I use the struct, it throws an error about [an object field at offset 4 that is incorrectly aligned or overlapped by a non-object field].
I use a byte to hold this place, then get the byte pointer to convert s2 or s3 struct; like this [ byte s3;]; but it’s so bad to use.
Is there any other way to specify this type directly?
I have no idea, I tried to add attribute UnmanagedType.IUnknown
and some others, but it still does not work.
11
You can’t use arrays (reference types) here; however, an inline array (which is similar to a “fixed buffer”) would work nicly:
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
Console.WriteLine(Unsafe.SizeOf<s4>());
// ^^^ 44 = 11 integers, as expected
var obj = new s4();
obj.s2[3] = 13;
Console.WriteLine(obj.s3[3]); // 13
[InlineArray(10)]
public struct s2
{
// this just defines the type for the inline array
private int w;
}
[InlineArray(10)]
public struct s3
{
// this just defines the type for the inline array
private int w;
}
[StructLayout(LayoutKind.Explicit)]
public struct s4
{
[FieldOffset(0)]
int i;
// changed accessibility to test
[FieldOffset(4)]
public s2 s2;
[FieldOffset(4)]
public s3 s3;
}
However: honestly, given that s2
and s2
have the same shape… I’m really not sure what the point of having them as separate types is here. Just having a single type and single field would seem to be fine.
If you’re not using .NET 8 or later; fixed buffers:
public unsafe struct s2
{
private fixed int w[10];
public int this[int index]
{
get
{
fixed (int* ptr = w)
{
return new ReadOnlySpan<int>(ptr, 10)[index];
}
}
set
{
fixed (int* ptr = w)
{
new Span<int>(ptr, 10)[index] = value;
}
}
}
}
public unsafe struct s3
{
private fixed int w[10];
public int this[int index]
{
get
{
fixed (int* ptr = w)
{
return new ReadOnlySpan<int>(ptr, 10)[index];
}
}
set
{
fixed (int* ptr = w)
{
new Span<int>(ptr, 10)[index] = value;
}
}
}
}
2