0

I have been studying pointer of c plus plus.

I created function called pp which takes reference as parameter. then print its memory address, value and size.

And I create variable a, b assigned it to 10, 25 indivisually.

And variable pa, pb which points to variable a, b.

My environment is MacOS M1 Architecture and I compiled it using c++17 version.

#include <iostream>

void pp(int & i) 
{
  std::cout << &i << " " << i << " " << sizeof(i) << "\n";
}

int main(int argc, char * argv[]) 
{
  int   a = 10;
  int   b = 25;
  int* pa = &a;
  int* pb = &b;

  pp(a);
  pp(b);

  return 0;
}

when I compile below my c++ code, output is like this.

0x16b802e7c 10 4
0x16b802e78 25 4

My question is about relation of memory address between variable a and b.

I have already know there is gap of 4 size in addresss because of size for integer is 4 bytes.

It's okay, but It confuse me that variable address of a is higher than address of b although variable a was created before initializing variable b.

when this code is compiled then executed in other platform, output is different.

address of variable a is lower than b.

So in my environment which is macOS, If I write code like below.

*(pb - 1) = 17;

It doesn't change value of a. because memory address b is lower than a although My expectinon is to change value of a.

If I want to change value of a accesing memory address, I have to add one to pointer of b like below.

*(pb + 1) = 17;

as a result, I want to know why this difference of memory allocation by platform is to be and what theory I have to know to understand how it works.

Might it be relations about endian?

Jay Lee
  • 11
  • 2
  • 1
    These are on a stack, going from top to bottom. – πάντα ῥεῖ Aug 14 '23 at 05:27
  • 4
    I believe both `*(pb - 1) = 17;` and `*(pb + 1) = 17;` are undefined behavior regardless of the stack layout. – Retired Ninja Aug 14 '23 at 05:28
  • 1
    The compiler is free to arrange the stack however it chooses. It does not even have to put your variables in stack memory _at all_. – paddy Aug 14 '23 at 05:29
  • Whoever in team enables address sanitizer for debugging and then it crashes in your code so you won't get any benefit from such hacking. Better describe what problem you are trying to solve. – Öö Tiib Aug 14 '23 at 05:44
  • Beware: you are far beyond what is specified by the language here, and memory organization is just an implementation detail. In fact, using C++17 does not matter here. What matters is the exact compiler (and linker if it matters) and the exact build options that you are using. Said differently, you are exploring a grey zone here, but no real world problem depends on that so most of us just do not care (depending on those details would mean that the program could break at any build environment change...). – Serge Ballesta Aug 14 '23 at 05:53
  • Typically stack "raises" backwards as opposed to heap. – freakish Aug 14 '23 at 05:55
  • To clarify that grey zone a bit more, the pointer `pb + 1` is actually valid and can be used to compare with other (valid) pointers derived from `b`. But it is undefined behavior to read or write memory via this pointer, as it points one-past-the-end of `b`. – paddy Aug 14 '23 at 05:58
  • The C++ standard specifies nothing - the relative locations in memory of `a` and `b` are unspecified. Although their addresses may compare as not equal, the result of strict inequalities (like `a < b` and `a > b`) are unspecified. By doing `*(pb + 1) = 17` your code exhibits undefined behaviour - so *any* outcome is possible - one *possible* outcome is overwriting `a` with the value `17`, another possible outcome is overwriting something else which may (in turn) result in your program being forceably killed by the host system (e.g. under unix, with a `SIGSEGV` signal). – Peter Aug 14 '23 at 06:33

1 Answers1

0

The stack on your implementation allocates (i.e., pushes) a new variable on the stack by decrementing the stack pointer by however many bytes the variable requires, and then constructing it at that location. For class types, this means calling a ctor, but for built-in types, such as int, it means doing nothing (unless you have provided an initializer).

When a variable is released (i.e., popped) from the stack, your implementation simply increments the stack pointer by the number of bytes the variable uses.

As was noted in the comments, stack operations are an implementation detail that may vary from compiler to compiler. The language standard does not require that the stack be implemented in any specific way.

tbxfreeware
  • 547
  • 1
  • 9