Back to Posts

The "sizeof" Operator in C#

Written by Cats-n-Coffee -

- Published on Tue Feb 06 2024


These are my notes and summaries written from watching various videos or reading articles and tutorials. I write summaries of content I enjoy because it helps me understand and dig deeper, and can help others clarify areas of grey. Please refer to the original content linked in the post for all the details.

Learning how C# works from watching Jamie King’s C# Types playlist. These are my notes to summarize his C# sizeof video.

While following the Vulkan tutorial on the official site and using the Silk bindings example which uses unsafe C#, we use the sizeof operator, which I had not used in previous .Net projects because they only used managed types and never had to check the size of anything.

What is it?

The sizeof operator in C# returns the size of a type in bytes at compile time, very much like what I remembered from C++. Which means we can’t get the size of managed type like classes with this operator. However, we can get the size of a struct, where the total size should be the sum of all members’ sizes.

Alignment and struct

While reference types like classes will get managed by the runtime (in a safe context) to align all members in an optimal way, when using unsafe C# and structs we need to be aware of the order in which members are declared. As shown in the video, we start with the following struct (showing a similar one):

struct MyStruct {
  public char myChar1;
  public int myInt;
  public char myChar2;
}

Adding all the members we get 8 bytes total (2 char for 2 bytes each, 1 int for 4 bytes), but if we print a sizeof(MyStruct) we will see 12. As well explained (and drawn!) in the video, we get 12 instead of 8 because each char sits on a slot of 4 bytes, resulting in wasting 2 bytes in each slot. To get around this, we can reorder our members, or use attributes.

Reordering Members

Our members reordered should be like this:

struct MyStruct {
  public char myChar1;
  public char myChar2;
  public int myInt;
}

Using Attributes

Going back to our first struct layout:

struct MyStruct {
  public char myChar1;
  public int myInt;
  public char myChar2;
}

To have the runtime align things for us, we’ll need to import a namespace:

using System.Runtime.InteropServices;

Then we can use the attribute above our struct. To get the runtime to optimize things for us we can use the Auto option:

[StructLayout(LayoutKind.Auto)]

There are 2 other options, the Sequential option will keep the order as we declared it, and the Explicit option will require us to use [FieldOffset(<offset here>)] attributes for each member because we are now in charge of manually placing each of them