none
Blittable documentation error? RRS feed

  • Question

  • OK so according to my reading a struct will be blittable if all of its member are.

    http://msdn.microsoft.com/en-us/library/75dwhxf7.aspx

    Also a 'one dimensional array of a blittable type' is also blittable.

    So how do I define a struct member that is a one-dimensional array and have the struct blittable?

    I mean if MS mean to declare it as a fixed buffer (unsafe) they should say so.

    Just declaring an array member like this:

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

            public byte[] buffer;



    Doesn't work, it causes the struct to no longer be blittable.

    I test for blittability incidentally by attempting to create a GC handle, so I know for sure if it is or isn't.

    The docs mean to say one of these I think:

    1. A fixed buffer (array) of blittable types is also blittable.
    2. There is some way to declare a [] that doesnt 'break' a structs blittability and I dont know what that is.
    3. An array variable (not a member) declared as shown above, IS blittable, but not when it is a member of a struct.

    It strikes me that the documentation needs improving, what do you think?

    The Cap'n

    Friday, September 12, 2008 11:01 AM

Answers

  • The document is correct, just a little confusing because there are so many concepts in one page.
    The important thing to remember is that object references (inside structs, for example) are not blittable. So any struct containing an array (which is always an object reference on the managed side) is not blittable. However, it can still be marshaled by specifying the array marshalling options, but a marshaled copy will always be made in this case.

    For example, if you have a managed struct with an array of elements, then on the managed side, the struct will contain a member that is an object reference to a managed array object. However, you can specify that for marshalling purposes, the array represents a COM SAFEARRAY or a fixed buffer, in which case, the marshalling code will create a SAFEARRAY in memory and copy the members into it, or create a new struct with a fixed-size buffer and copy the elements into that buffer.

    One of the main differences you have to remember is that usually in an unmanaged C-ish language, an array is really a pointer to the first element, but in the managed world, an array is itself an object, which internally contains a pointer to an element list in memory. That's why it's not directly blittable by default. Unmanaged code would have no idea what to do with that pointer.


    -Rob Teixeira
    • Marked as answer by Zhi-Xin Ye Wednesday, September 17, 2008 11:54 AM
    Friday, September 12, 2008 5:38 PM

All replies

  • A struct is a value type.  The page to you linked specifically mentions that value types are not blittable.  Using GCHandle on value types is not possible, it can only wrap references.  It is not a good test for blittability. 

    The C# language has the "fixed" keyword to declare a fixed size buffer.  It requires the unsafe keyword.

    Hans Passant.
    Friday, September 12, 2008 11:34 AM
    Moderator
  • Hi

    Well this just goes to underline what I'm saying about the docs, you are not quite right and I think there is often confusion over this subject.

    struct value types ARE blittable IF every member is blittable, this enables the marshaler to pin the managed memory (that comprises the value type) and pass a pointer to it, when calling unmanaged code.

    If the type is not blittable, then the marshaler must marshal it in a more complex manner and it ends up creating a temp copy that satifies the storage expectations of the unmanaged callee.

    So far as I know, you can ONLY allocate a GCHandle of type Pinned, IF the data is blittable, else you get this exception:

    "An instance with nonprimitive (non-blittable) members cannot be pinned."

    If you can get a pinned handle and do not get that exception, then you can be 100% certain that the data IS blittable.

    Anyway, certain 'value types' must be blittable, a Byte is blittable yet is also a struct, and therefore a value type...

    What I am seeking is clarification on this:

    "One-dimensional arrays of blittable types, such as an array of integers. However, a type that contains a variable array of blittable types is not itself blittable."


    If that is indeed blittable, then HOW would it be declared and CAN it be a member of a (otherwise) blittable struct?

    I dont think the docs as the stand, answer that question.
    Friday, September 12, 2008 11:57 AM
  • The document is correct, just a little confusing because there are so many concepts in one page.
    The important thing to remember is that object references (inside structs, for example) are not blittable. So any struct containing an array (which is always an object reference on the managed side) is not blittable. However, it can still be marshaled by specifying the array marshalling options, but a marshaled copy will always be made in this case.

    For example, if you have a managed struct with an array of elements, then on the managed side, the struct will contain a member that is an object reference to a managed array object. However, you can specify that for marshalling purposes, the array represents a COM SAFEARRAY or a fixed buffer, in which case, the marshalling code will create a SAFEARRAY in memory and copy the members into it, or create a new struct with a fixed-size buffer and copy the elements into that buffer.

    One of the main differences you have to remember is that usually in an unmanaged C-ish language, an array is really a pointer to the first element, but in the managed world, an array is itself an object, which internally contains a pointer to an element list in memory. That's why it's not directly blittable by default. Unmanaged code would have no idea what to do with that pointer.


    -Rob Teixeira
    • Marked as answer by Zhi-Xin Ye Wednesday, September 17, 2008 11:54 AM
    Friday, September 12, 2008 5:38 PM