Reputation: 2125
I'm in the process of learning about reference types, value types, the stack and the heap and the differences between them.
Now I've ran into something that's a bit mind-boggling to me. Here's a code example to illustrate what I mean
void Main()
{
int foo = 0;
PassFoo(ref foo);
Console.WriteLine(foo);
}
void PassFoo(ref int bar)
{
bar = 1;
}
As it stands now the output would be 1
as long as we use the ref keyword. If we remove the ref keyword then the output will be 0
. I understand that this is because integers are value types and when we pass foo
by value we are copying the value bit by bit to bar
but when we add the ref keyword we are instead passing only the memory adress of foo
on the stack and that is also why we're changing the value of foo
in this example. Am I right so far?
... Now to the part that confuses me. My understanding of how the stack works is that it can only access the currently running stack frame. That's why PassFoo
can't directly access foo
. I have also learned that value types are stored where they are declared. So this is what confuses me, when we're passing foo
by reference we're passing the memory adress of foo
to bar
right? But shouldn't this be inaccessible to PassFoo()
because it is running in a different stack frame?
I realize that I probably don't quite have the right understanding of how this works, so a clarification would be greatly appreciated.
Upvotes: 1
Views: 638
Reputation: 203842
My understanding of how the stack works is that it can only access the currently running stack frame.
That's not true. Under the hood, a method is able to access the memory from any stack frame. The C# compiler simply applies constraints such that, in most situations, references to locations on the stack are not exposed outside of that method's body. This situation, the use of the ref
keyword, is one exception to that situation. Once you get to lower layers of abstraction, namely the IL code that the compiler generates, there is no constraint at all that would prohibit accessing a stack from another method's body.
The first half of your question is a valid explanation as to what's going on.
Upvotes: 4
Reputation: 477
That's not really true. My understand is that we can't directly access foo
, because we didn't know the reference(in c#) or address(in c). Think about we are programming in c, you can access any memory. So we use pass by reference, than we could access the value of foo by the reference. You can think stack frame as physical function chunk to manipulate memory and function easier.
Here's an article about stack.
Upvotes: 0
Reputation: 928
If the method calls another method then the new method creates its stack frame on the top of the stack. In this way each new method can allocate its own local variables in its own portion of the memory allocated to the stack, and stack is also use to store parameters and return values passed between methods, that's why it the pointer to foo that is stored in bar parameter is visible.
Upvotes: 0
Reputation: 349
Your understanding is quite good. Passing a value type by reference will cause the framework to box that parameter, i.e. wrapping a reference to it in an object that is created on the heap. I am not sure what you mean by "stack frame". Both methods ("Main" and "PassFoo") would have access to the same stack.
Upvotes: -2
Reputation: 1804
When you pass foo into PassFoo you are passing the address of where foo resides. Since PassFoo knows where the value of foo is stored, it can change the value in that memory address. The stack frame for PassFoo contains only the address of the variable. The following is equivalent C code with pointers
#include <stdio.h>
void PassFoo(int* bar)
{
*bar = 1;
}
int main()
{
int foo = 0;
PassFoo(&foo);
printf("%d", foo);
return 0;
}
Upvotes: 0