• We’re currently investigating an issue related to the forum theme and styling that is impacting page layout and visual formatting. The problem has been identified, and we are actively working on a resolution. There is no impact to user data or functionality, this is strictly a front-end display issue. We’ll post an update once the fix has been deployed. Thanks for your patience while we get this sorted.

Pointers with native types

brandonb

Diamond Member
I have a question, I'm trying to think of what happens behind the scenes when you use a native type in a programming language.

I'm going to use VB.net for an example:

Dim ourInteger as Integer

Or C++:

int variable;

That is obviously 4 bytes in memory, but the question being, is there a pointer being created that points to that Integer in memory either in the code memory or data memory for the program? So if you declare that does it end up using 8 bytes in memory, 4 for the integer, and 4 for a pointer to that integer that is assigned to the ourInteger name?

I remember way back with C++ that constants are considered pointers, and declarations are a constant so to speak aren't they? Just a bit confused about an int this doesn't seem as clear.

Can anybody clear this up for me what happens behind the scenes in memory when you do a simple declartion with just an integer, how does the program find that integer in memory when trying to use it? Is there a pointer?
 
Local variables are normally created on the stack (see wiki for what "the stack" is.)

The way the stack works there is one "allocation" for all local variables and only a single "stack pointer" to the set of them. So the int only requires 4 bytes.

Now if you use new or malloc then there is an allocation for the pointer variable (possibly on the stack) plus an allocation for the int.

int* foo = new int ;

= 4 on the stack (pointer variable) and 4 in the heap (the int).
 
What dave said is correct. Generally (not always) when you have a local variable it is pushed onto the stack. If you have a variable that is a pointer, it too is pushed onto the stack.

The address is filled with useful information, but a pointer is not necessarily created.

An analogy would be, you build a house, that house is at an address (the int). If someone goes to that address the house is there. If you put a sign up somewhere (the pointer) with your address on it, you now have something that lets others know exactly where you live. That sign has a location (or address if you will).

Can you build house without a sign pointing to it? yep. Does creating a variable mean that you create a pointer? Nope, but it does mean you take up address space.

Now technically, at the very low level, there is (as Dave mentions) a stack pointer. It points at the top of the stack, when someone puts something else on the stack, the stack pointer is increased. If you want to access that thing, then you have to do some math with the stack pointer (IE stack pointer - 8 = my integer) to extract the data. The compiler is in charge of managing how the stack pointer behaves, it does a good job of remembering exactly how many bytes back each variable is.

So longwindedly, there is a pointer in every program, no matter what, however, making new variables doesn't create new pointers.
 
I think the distinction between stack and heap might obfuscate the issue a little. Regardless of where it is located, a region of memory contains bits, and exists at an address. For local variables the compiler just hides the pointer arithmetic/dereferencing. At the assembler level wouldn't changing the value of an integer on the stack, or one declared on the heap, look identical except for the use of SS:ESP in the first case, and DS:EBP (or some other pointer) in the second?
 
At the assembler level wouldn't changing the value of an integer on the stack, or one declared on the heap, look identical except for the use of SS:ESP in the first case, and DS:EBP (or some other pointer) in the second?

Well, no, not really. You can't access the heap like you access the stack (in most modern programming languages that is). Nor can you necessarily make the assumption that one value allocated to the heap is going to be directly below the next object in the heap. For that reason, unless dealing with arrays, pointer arithmetic is solely confined to the stack. For heap stuff, the address of the item on the heap is stored on the stack, and accessed by getting that value from the stack. No register contains the heap address quite like the ESP register holds the stack address.

Just a small note, EBP is the base pointer, and for most compilers holds the top of the stack for the particular function that you are in, ESP always (or should always) holds the current position of the stack. EDI and ESI are generally used as pointer registers (source, destination) and edx, ax, cx, bx, are usually used as general purpose registers that do have some stoic properties and general uses associated with them.
 
To me the main difference is that for a single variable using the heap you'll always need the pointer variable _and_ the value, both int* i and the value that *i points to.

With the stack, because of the stack pointer, you can have just int i with no pointer variable needed. The assembly code to look up the value of i as a stack variable is (stack pointer) + a fixed offset known at compile-time.
 
Thanks for the clarifications. My assembly is very rusty. 🙂. I think the main point I was trying to get across is that ultimately they are the same thing. You can take the address of a local variable on the stack and manipulate it through a pointer, but as Dave notes you don't have to because the compiler has enough information to know what do do internally.
 
Thanks guys for the clarification. That was exactly what I was looking for. I should learn assembler, just to help understand some of this stuff (I'm a nerd that way).
 
One thing you might find useful is to ask your compiler to compile without assembling. In gcc, its the -S flag.

E.g., try this code:
myfunction.c:
Code:
int myFunction(int x) {
  int local1;
  int local2;
  local1 = x + 1;
  local2 = local1 * x;
  return x + local1 + local2;
}

Now run gcc -S myfunction.c -o myfunction.S (make sure you don't use optimizations)
Now look at myfunction.S.

Next, try compiling this the same way:
Code:
int myfunction(int x) {
  int local1;
  return x;
}
And have a look at the differences.
 
Back
Top