What's the size of this C# struct?
Asked Answered
D

6

11

Is it 12 bytes or 16 bytes when stored in a List<DataPoint>?

public struct DataPoint
{
    DateTime time_utc;
    float value;
}

Is there any sizeof function in C#?

Dickie answered 27/9, 2010 at 14:11 Comment(3)
I hope you are aware that each instance of this struct will be boxed when put in a list, so add the space for the pointer.Pender
@ToxicAvenger: it will not be boxed when you put it inside a List<DataPoint>. It would be boxed in an ArrayList or List<object> though.Rowles
This is more specific, but possibly a duplicate of #3362486Fredric
S
14

Take a look at @Hans Passant's answer here for interesting background on this issue, esp. with regard to the limitations of Marshal.Sizeof.

Silky answered 27/9, 2010 at 14:17 Comment(0)
A
8

The CLR is free to lay out types in memory as it sees fit. So it's not possible to directly give "the" size.

However, for structures it's possible to restrict the freedom of the CLR using the StructLayout Attribute:

  • Auto: The runtime automatically chooses an appropriate layout.
  • Sequential: The members of the object are laid out sequentially and are aligned according to the StructLayoutAttribute.Pack value.
  • Explicit: The precise position of each member is explicitly controlled.

The C# compiler automatically applies the Sequential layout kind to any struct. The Pack value defaults to 4 or 8 on x86 or x64 machines respectively. So the size of your struct is 8+4=12 (both x86 and x64).


Unrelated from how a type is laid out in memory, it's also possible to marshal a type in .NET using the Marshal Class. The marshaller applies several transformations when marshalling a type, so the result is not always the same as the way the CLR laid out the type. (For example, a bool takes 1 byte in memory plus alignment, while the marshaller marshals a bool to 4 bytes.)

Anoa answered 27/9, 2010 at 14:27 Comment(2)
Note it's possible with the IL sizeof instruction to get the "final" CLR size of a struct, taking into account padding and any other alignment operations. See my blog post for how to use it and more differences (note: I wrote a wrapper library that can be called from C#)Launder
It's 16 on x64 as is, without attributes. The Pack value defaults to 4 or 8 on x86 or x64 machines respectively, but then you contradict yourself.Cephalothorax
U
7

Marshal.SizeOf()

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

Unthankful answered 27/9, 2010 at 14:12 Comment(2)
You could add the solution to his question: 16 bytes (8 bytes + 4 bytes + 4 bytes alignment)Morningglory
Marshal.SizeOf() does not return the size of a managed struct, only the unmanaged version of it. Check Steve's answer.Dissolve
Z
4

It will be 12 bytes (4 for float, 8 for DateTime); Marshal.SizeOf will return 16 because the default packing is 8 bytes aligned. This is a good article on structs and packing. It gives a full description of whats actually happening.

Zanezaneski answered 27/9, 2010 at 14:16 Comment(0)
M
0

Try Marshal.SizeOf(typeof(DataPoint))

Millibar answered 27/9, 2010 at 14:15 Comment(0)
R
0

The following code is based on this StackOverflow question and answers:

        /// <summary>
        /// Computes the size of the given managed type. Slow, but reliable. Does not give the same result as Marshal.SizeOf
        /// NOTE: this is not the same as what is the distance between these types in an array. That varies depending on alignment.
        /// </summary>
        public static int ComputeSizeOf(Type t)
        {
            // all this just to invoke one opcode with no arguments!
            var method = new DynamicMethod("ComputeSizeOfImpl", typeof(int), Type.EmptyTypes, typeof(Util), false);
            var gen = method.GetILGenerator();
            gen.Emit(OpCodes.Sizeof, t);
            gen.Emit(OpCodes.Ret);
            var func = (Func<int>)method.CreateDelegate(typeof(Func<int>));
            return func();
        }

I think the question you are probably wondering, is not what is the size of the type but what is the distance between two contiguous elements in the List. This is because alignment can play a role, as mentioned by others.

I believe the solution to that problem would best be achieved using Marshal.UnsafeAddrOfPinnedArrayElement(), but is very difficult to use correctly, particularly because the List does not expose publicly the backing array.

Retentive answered 14/1, 2019 at 1:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.