5

After reading a bit about the Int32 struct in C#, I realized that int and Int32 are synonymous. In the source code of Int32 struct, there is a internal int m_value field.

If my knowledge is right, the value that we assign to a int variable is stored in m_value (Am I right?). But my doubt is how the value gets stored in m_value when we give int i = 7;.

I don't see any implicit operator either in the Int32 struct source code so that the value could get stored in m_value.

Can any one help me with this?

Soner Gönül
  • 97,193
  • 102
  • 206
  • 364
  • 1
    Voted for reopen. Those are different questions. – Soner Gönül Dec 11 '15 at 12:06
  • @SonerGönül: i don't know the former proposed duplicate, but this seems to answer OP's question( which is actually: how is System.Int32 initialized when i assign an `int` variable): http://stackoverflow.com/questions/25449498/instantiation-and-initialization-of-value-types-vs-reference-types _"int is a built-in type. The compiler knows how to generate IL for it. The type of int is "baked into" the CIL the compiler generates for the assignment: `.locals init ([0] int32 a) ldc.i4.s 5 stloc.0`"_ – Tim Schmelter Dec 11 '15 at 12:10
  • @TimSchmelter It was [this one](http://stackoverflow.com/questions/16113850/if-int32-is-just-an-alias-for-int-how-can-the-int32-class-use-an-int) – James Thorpe Dec 11 '15 at 12:11
  • @TimSchmelter you can see it in the [edit history](http://stackoverflow.com/posts/34223128/revisions) - between edit 2 and 3 – default Dec 11 '15 at 12:13
  • @TimSchmelter That was another question voted as a duplicate. And yes, the question you linked fits better. – Soner Gönül Dec 11 '15 at 12:13

3 Answers3

5

int in C# represents the same thing as int32 in CIL, which is a 4-byte primitive generally treated as a signed number. (Though CIL can do unsigned operations on it without a cast).

It's one of the lowest-level building blocks from which we can go on to create more complicated structures and classes.

But as such, it doesn't have any methods defined on it.

System.Int32 meanwhile looks pretty much like a struct that wraps an int/int32 and does provide some methods.

Let's consider it as that; let's think about what it would be like in a world without int being aliased with System.Int32:

In this hypothetical situation, we would only be allowed to use the methods System.Int32 provides if we treated it as a special "boxed int" type, creating a System.Int32 from an int when we needed it, and extracting the int back again when we needed that.

So, without aliasing to do (3).CompareTo(2) we would have to do:

new System.Int32{m_value = 3}.CompareTo(2)

But consider that the in-memory representation of int is 4 bytes and the in-memory representation of System.Int32 is the same 4 bytes. If we didn't have a strong type-system that barred considering one type as another type we could just treat one as the other whenever we wanted.

Now, C# does not allow us to do this. E.g. we can't do:

public struct MyInt32
{
  private int _value;
}
/* … */
MyInt32 = 3;

We would need to add a cast method that would be called, or else C# will just refuse to work on it like this.

CIL though has no such rule. It can just treat one type as another layout-compatible type whenever it wants. So the IL for (3).CompareTo(2) is:

ldc.i4.3 // Push the 32-bit integer 3 on the stack.
ldc.i4.2 // Push the 32-bit integer 2 on the stack.
call instance int32 [mscorlib]System.Int32::CompareTo(int32)

The call at the end just assumes that the 3 is a System.Int32 and calls it.

This breaks the rules of C# type-safety, but those rules are not CIL's rules. The C# compiler also doesn't have to follow all of the rules that it enforces.

So there's no need to put anything into m_value, we just say "oh those four bytes there, they're the m_value field of a System.Int32", and so it is magically done. (If you know C or C++ consider what would happen if you had two structs with equivalent members and cast a pointer to one of those types to void* and then back to a pointer of another. It's a bad practice and IIRC undefined rather than guaranteed, but the lower-level code is allowed to do those sort of things).

And that is how aliasing works; .Net languages' compilers special-case the cases where we need to call a method on a primitive to do this sort of type-coercion that C# code itself does not allow.

Likewise, it special cases the fact that a value-type cannot hold a field of its own type, and allows System.Int32 to have an int field, though generally struct S { public S value; } would not be allowed.

Jon Hanna
  • 110,372
  • 10
  • 146
  • 251
0

That's just how the language works, man!

In the stateent

int i = 7;

You are creating a variable of Int32. (i.e. the int i part). However, you are assigning it with a 7. A 7 in C# (and in many other languages) is called a literal. This means that 7 is already an instance of Int32! It's like this:

Suppose you have a class

public class ClassA {
    public int i;
}

And an instance of ClassA:

ClassA obj = new ClassA ();
obj.i = 1;

And then you do this:

ClassA a = obj;

And you say, "I don't see any implicit operator in ClassA so that the value could get stored in i."

But obj is already a legit object! Just like 7.

Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • You have introduced a `new ClassA()` so it's not analogous. To be analogous it would have to be `ClassA obj = 1` **and** not have any implicit operator defined. It won't work in C#, but C# doesn't have to play by the rules C# enforces when it does aliasing. – Jon Hanna Dec 11 '15 at 12:41
0

It's rather hard to follow what's going on when reading the source of the core framework.

"how the value gets stored in m_value when we give int i=7;"

Firstly, when the C# compiler sees int, it just pretends you said System.Int32 instead (*). Similarly when it sees 7, it says "aha! That's an integer literal. I'll store it in a System.Int32". So then it creates the variable i (of the right type), and initializes it with the value it created.

(*) That means that the source http://referencesource.microsoft.com/#mscorlib/system/int32.cs,225942ed7b7a3252 has:

public struct Int32 : *various bases*
{
    internal Int32 m_value;

... which is ever so slightly confusing (and wouldn't normally be legal).