The nitty gritty of primitive data types in .NET

The C# Language Specification 4.0 indicates that

C# provides a set of predefined struct types called the simple types. The simple types are identified through reserved words, but these reserved words are simply aliases for predefined struct types in the System namespace, as described in the table below.

image

So far so good.

However, when we uncover the struct definition of Int32 by means of disassembler we quickly figure out that it has a field of the type int, namely m_value.
namespace System
{
    public struct Int32
    {
        internal int m_value;
    }

}
So this seems to be a bizarre cyclic definition.  In addition, the field m_value is never accessed neither get nor set accessors.

The question is how this happens and how exactly the primitive types store their values? 

Answer:

(Below is just my interpretation for this question after digging some relevant specification documents.  The exact answer may differ to some degree)

Let’s analyze the CIL code that is generated by the following C# code.

static int Main(string[] args)
{
            //case 1: ordinary parameter names
            int paramInt = 0xABCD;
            Int32 paramInt32 = 0x1234;

            //case 2: parameter names are identical to keywords
            int int32 = 0xDCBA;
            Int32 Int32 = 0x4321;

            //all parameters are used just to suppress compiler optimization
            return paramInt + paramInt32 + int32 + Int32;
}

image

What can be seen in CIL code that both int’s and Int32’s are converted to clr type int32 (See Table I.1 in Built-in value and reference types header of CLI Specification 6th Edition).

So when compiling, the conversion is not

                                 int->Int32->int32

but rather it is

                                 int->int32

                                 Int32->int32

.

So the cycle is broken by converting simple types directly to the CLI types when compiling.  The CLI code of System.Int32 struct is generated with a field of CLI type int32 which is perfectly valid.

image

Since the 4-byte field m_value is the first and only field, m_value is aligned directly with the whole value of the 4-byte struct Int32 in the corresponding memory location.  That’s why there is no get/set accessors of m_value in the struct Int32. The same explanation can be applied to all other primitive data types in .NET.

Acknowledgements: I would like to thank to the members of Joel on Software Discussion Community for sharing their knowledge under this post.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s