2

i have to define a struct works with unsafe code, so i have to set the FieldOffset values of every fields. But i cannot define size of pointer. Here is the code :

[StructLayout(LayoutKind.Explicit)]
public struct SomeStructO
{
    public SomeStructO(int theNumber)
    {
        TheNumber = theNumber;
        Coordinates = PointF.Empty;
        SomeNumbers = null;
    }

    [FieldOffset(0)]
    public PointF Coordinates;

    [FieldOffset(sizeof(float) * 2)]
    public int[] SomeNumbers;

    [FieldOffset(sizeof(float) * 2 + IntPtr.Size)]
    public int TheNumber;
}

gives an error because IntPtr.Size is not a constant expression and ofcourse this one doesnt compile either:

Marshal.SizeOf(typeof(IntPtr))

when it comes down to question title, it is more how i can set specific "32bit 64bit compile" pointer data size in FieldOffset definition.

Edit: and also i can not put the "public int[] SomeNumbers;" field at the end of the struct, because i have 2 different arrays in my struct.. like "public int[] SomeOtherNumbers;"

Ken Y-N
  • 14,644
  • 21
  • 71
  • 114
Ibrahim Ozdemir
  • 613
  • 1
  • 5
  • 18
  • You have a much bigger problem, you cannot marshal a struct that contains an array. Unless you use UnmanagedType.ByValArray, it does not look like you want that. Only declaring it IntPtr and marshaling the array yourself is a workaround. Do check this against the native declaration, it is unusual because it is such a memory management headache. The solution to the stated problem is otherwise *very* trivial, simply don't use [FieldOffset]. It doesn't do anything. LayoutKind.Sequential is plenty good enough. – Hans Passant Feb 12 '17 at 23:55
  • Out of curiosity. why are you giving your struct a `StructLayout` attribute? Perhaps there is another approach entirely that would be better suited for what you are trying to do. – Abion47 Feb 13 '17 at 00:18
  • i have to use a struct in an unsafe block and it gives error when i dont use StructLayout – Ibrahim Ozdemir Feb 13 '17 at 00:24
  • How are you using the struct in the unsafe block? – Abion47 Feb 13 '17 at 00:34
  • actualy i am researching about that right now, i have not figure it out yet. I am trying .net's PointF struct since it can be used in unsafe block, i was able to get the data but could not write some float values directly to pointers float address :( – Ibrahim Ozdemir Feb 13 '17 at 00:41
  • i found a way of doing that Abion47: ` float* pointP = (float*)item; *(pointP + 0) = 45; //x value *(pointP + 1) = 55; //y value` – Ibrahim Ozdemir Feb 13 '17 at 00:51
  • That use of pointers seems arbitrary. Just because you are operating in an unsafe context doesn't mean you need to use pointers for every single thing. You could just as easily use `item.X = 45; item.Y = 55;` – Abion47 Feb 13 '17 at 01:01
  • the reason i am trying to figure out about unsafe code is; i have lots of vertexes in 3d space and they are connected eachother with triangle combinations, and number of these connections are not fixed like every vertes has 2 other vertex to make a triangle.. some vertexes have more than 2 connections, so i need dynamic size arrays. since i cannot create a List object for every little vertext and i cannot use an array directly (because it is hard to deal with indexing operations), i had to create a lighter List structure. Thats why i need to learn this stuff. – Ibrahim Ozdemir Feb 13 '17 at 01:32
  • Why can't you have a List for every vertex? A List is just an array that automatically resizes if the required size is greater than the array's length. It's plenty lightweight, especially if you set an initial `Capacity` large enough so that the array doesn't need to be resized very often. Pointers are lightweight, sure, but they are also very dangerous to use in the way you are describing. If you freely assign to memory with a pointer, there is no guarantee that you won't overwrite memory that is being used by something else. There's a reason that C# discourages their use if at all possible. – Abion47 Feb 13 '17 at 01:49
  • no i have system written in other language, it is realy well written and tested many many times. About using Lists for every vertex; List is a class, classes are (i think) so big for vertices. think about a simple (maybe a game scene), that scene will have like 2.000.000 vertices.. can you think about doing that with classes and think about garbage collector stuff.. anyway i think i am handling the situtaion; i will use a List for main vertex list and every vertices wil have an integer sub array (my array structure) so i think i can get closer to my old code. – Ibrahim Ozdemir Feb 13 '17 at 02:23

2 Answers2

1

i ended up putting a symbol on my project and using int and long sizes to declare a pointers size

[StructLayout(LayoutKind.Explicit, Pack = 2)]
public struct VertexO
{
    public VertexO(Vector location)
    {
        Location = location;
        Neighbours = new IntListO();
        Triangles = new IntListO();
    }
    public VertexO(float x, float y, float z) : this(new Vector(x, y, z)) { }

    [FieldOffset(0)]
    public Vector Location;

    [FieldOffset(sizeof(float) * 3)]
    public IntListO Neighbours;

    #if WIN64
    [FieldOffset(sizeof(float) * 3 + (sizeof(int) * 2 + sizeof(long)))]
    #else
    [FieldOffset(sizeof(float) * 3 + (sizeof(int) * 2 + sizeof(int)))]
    #endif
    public IntListO Triangles;
}

IntList is another struct that has 2 int and 1 pointer fields:

    [StructLayout(LayoutKind.Explicit, Pack = 2)]
public struct IntListO
{

    //public IntListO()
    //{
    //    Handle = IntPtr.Zero;
    //    FCount = 0;
    //    SizeOfItem = sizeOfItem;
    //    FCapacity = 0;
    //}

    private static int ItemSize = 4;//size of integer

    [FieldOffset(0)]
    private int FCount;

    [FieldOffset(sizeof(int))]
    private int FCapacity;

    [FieldOffset(sizeof(int) * 2)]
    private IntPtr Handle;
}

so with

#if WIN64
[FieldOffset(sizeof(float) * 3 + (sizeof(int) * 2 + sizeof(long)))]
#else
[FieldOffset(sizeof(float) * 3 + (sizeof(int) * 2 + sizeof(int)))]
#endif

i am actually able to get the right pointer size.

Bytheway i used "Pack = 2" for aligning bytes most reasonably. By default it is 0 and it adds extra size when i use Marshal.SizeOf(typeof(VertexO)), and i tested with some vertex and triangle test, it is working great.

thanks you guys

Ibrahim Ozdemir
  • 613
  • 1
  • 5
  • 18
-1

with unsafe code, so i have to set the FieldOffset values of every fields

Why do you need to specify FieldOffset for every field? If you use LayoutKind.Sequential and the appropriate Pack size in your StructLayout attribute, you should not need to specify the exact FieldOffset like you are trying to do with LayoutKind.Explicit.

Something like this is probably what you want:

[StructLayout(LayoutKind.Sequential)]
public struct SomeStructO
{
    public SomeStructO(int theNumber)
    {
        TheNumber = theNumber;
        Coordinates = PointF.Empty;
        SomeNumbers = null;
    }

    public PointF Coordinates;

    [MarshalAs(UnmanagedType.LPArray)]
    public int[] SomeNumbers;

    public int TheNumber;
}
Tim
  • 5,940
  • 1
  • 12
  • 18
  • When using the `UnmanagedType.LPArray`, you need to also specify the `SizeConst` and `SizeParamIndex` fields of the attribute. Also, it's worth noting that in C# all structs have a sequential `StructLayout` by default, so that attribute is redundant. – Abion47 Feb 13 '17 at 00:26
  • Agreed on both points. SizeConst doesn't have to be specified if this is only going out to an API (managed to unmanaged) in which case the size of the array will be used to determine how much to copy and pin; but if it is coming back from an unmanaged into managed code, the SizeConst would be required. Not sure how the OP will be using this so it is good to point that out. Thanks – Tim Feb 13 '17 at 00:35