1

I am running the following program in code blocks with GNU GCC as compiler on windows platform. Here in this program I want to check whether integer declared in function changes memory location. I know due to compiler optimization it may happen sometime that it will keep same address for variable even if it declared multiple times. But I am calling it million times then also it takes same address. I also tried it with volatile keyword even with volatile keyword it shows same output.

#include <iostream>
using namespace std;
int* test (int a, int b)
{
   int c=0;
   c=c+a+b;
   return &c;
}

int main()
{
  int* pre;
  pre = test(5,9);
  int i=0;
  for( i=0;i<1000000;i++)
  {
    int* cur = test(i,i+6);
    if(cur!=pre)
    {
        cout<<"wrong";
    }
}
cout<<i;
 return 0;
}
hyde
  • 60,639
  • 21
  • 115
  • 176
krishna
  • 413
  • 2
  • 10
  • 25
  • 2
    `c` is stack allocated memory, so it is pushed and popped from the stack each function call in the loop, I wouldn't be surprised for it to have the same address each time – Cory Kramer Jan 05 '18 at 16:20
  • 2
    What is C about this? – Yunnosch Jan 05 '18 at 16:20
  • Once an object is destroyed, it's address may be reused by another object in the future. `c` is destroyed at the end of `test`, so it's address may be reused, including by future instances of `int c`. Dereferencing the returned pointer, which no longer points to an object, would be undefined behavior. – François Andrieux Jan 05 '18 at 16:21
  • @0xDEADBEEF returning &c isn't undefined as long as it's not derefferenced. – UKMonkey Jan 05 '18 at 16:21
  • @0xDEADBEEF nonsense. It is **NOT** undefined behavior, it is very well defined behavior. In fact, this program does not contain any undefined behavior as far as I can see. – SergeyA Jan 05 '18 at 16:21
  • @FrançoisAndrieux wrong. Using the pointer the way OP is using it is not undefined behavior. – SergeyA Jan 05 '18 at 16:22
  • 1
    @SergeyA: Per C 2011 [N1570] 6.2.4 2, “The value of a pointer becomes indeterminate when the object it points to (or just past) reaches the end of its lifetime.” It may then be a trap representation, and merely using its value has undefined behavior (confirmed in J.2). – Eric Postpischil Jan 05 '18 at 16:29
  • `int* test (...) { int c=0; ... return &c; }` is bad. – chux - Reinstate Monica Jan 05 '18 at 16:32
  • Why should it be different ? – Jabberwocky Jan 05 '18 at 16:32
  • @EricPostpischil this is C, and the question is a C++ one (even if tagged with C). Also, the quote is very vague, as the word 'using' is not explained. Is it considered 'using' the pointer to assign the variable to something else? Because here it is not the pointer which is used, it is the variable which holds it. – SergeyA Jan 05 '18 at 16:33
  • 1
    The variable `c` terminates it's lifetime at the end of the function where it's declared!!! The scope of the variable `c` is only inside the function `test`!!! Then when the function returns the pointer of the `c` variable the lifetime of `c` is already terminated!!! – Sir Jo Black Jan 05 '18 at 16:34
  • @chux I am just testing the concept – krishna Jan 05 '18 at 16:34
  • _"I want to check whether integer declared in function changes memory location"_ The answer is rather uninteresting, though. This is an implementation-defined thing that programming languages above the assembly level exist to abstract away and avoid you worrying about. Wanting a practical example of how the compiler achieves something isn't bad, but ultimately I'd say not to worry too much about things like this. – underscore_d Jan 05 '18 at 16:35
  • 1
    Be careful, @EricPostpischil: the actual quote from C2011 J.2 is "The value *of an object with automatic storage duration* is used while it is indeterminate" (emphasis added). That does not happen in the code in this question, as the pointer value involved is not the value of any object. – John Bollinger Jan 05 '18 at 16:37
  • @SergeyA https://stackoverflow.com/questions/1866461/why-should-i-not-try-to-use-this-value-after-delete-this/1866543#1866543 – François Andrieux Jan 05 '18 at 16:40
  • 1
    I'm furthermore inclined to interpret "the value of a pointer" as "the value of an object of pointer type", for it seems to indicate that a value is something that a "pointer" *has*, not that it *is*. – John Bollinger Jan 05 '18 at 16:43
  • @FrançoisAndrieux linked answer lacks any authoritative references. – SergeyA Jan 05 '18 at 16:54
  • @SergeyA: C++ has similar rules. From the 2017 draft (N4659) 6.7 4: ”When the end of the duration of a region of storage is reached, the values of all pointers representing the address of any part of that region of storage become invalid pointer values (6.9.2). Indirection through an invalid pointer value and passing an invalid pointer value to a deallocation function have undefined behavior. Any other use of an invalid pointer value has implementation-defined behavior.” So, for C++ it may be implementation-defined rather than merely undefined as in C. – Eric Postpischil Jan 05 '18 at 18:40
  • @JohnBollinger: That is **a** quote from J.2, not **the** quote. Just above the item you quoted is “The value of a pointer to an object whose lifetime has ended is used (6.2.4).” – Eric Postpischil Jan 05 '18 at 18:43
  • Well then, @EricPostpischil, I apologize for interpreting you to be saying that the actual quote you presented, "The value of a pointer becomes indeterminate when [...]", was relevant to your argument. In fact, all of annex J is anyway informative, not normative, so we should consult section 6.2.4 for the relevant normative provision. The only text I see there on which J.2 could be basing its point is that immediately preceeding *your* original quote: "If an object is *referred to* outside of its lifetime, the behavior is undefined" (emphasis added). That does not support your position. – John Bollinger Jan 05 '18 at 19:28
  • @JohnBollinger: Reread my comment. You will see that the “The value of a pointer…” text I cited is a **correct** quote from 6.2.4 2, and I explicitly labeled it as from 6.2.4 2. Given that it is correctly quoted text from 6.2.4 2 cited as 6.2.4 2, there was no reason for you to claim it was an incorrect citation from J.2. After that citation, I wrote a sentence drawing conclusions from it, and I parenthetically mentioned J.2 to say it supported those conclusions. I did not say the preceding quote, which was from 6.2.4 2, came from J.2. You just made a mistake thinking the quote was from J.2. – Eric Postpischil Jan 05 '18 at 19:43
  • @JohnBollinger: Re “The only text I see there on which J.2 could be basing its point…”: As my original comment says, 6.2.4 2 says “The value of a pointer becomes indeterminate when the object it points to (or just past) reaches the end of its lifetime.” Since it is indeterminate, it may be a trap representation, and therefore using it may have undefined behavior. – Eric Postpischil Jan 05 '18 at 19:49
  • @EricPostpischil, I have read your comments and the relevant sections of the standard carefully. Let us at this point agree to disregard J.2 altogether, as it is non-normative. For the sake of argument, I will also accept for the moment that the end of an object's lifetime can cause an erstwile valid pointer value to become a trap representation. It still does not follow that "merely using its value has undefined behavior". I believe the (only) relevant rules for this would be in 6.2.6.1/5, and although that covers a lot of cases, "merely using" is too broad a characterization. – John Bollinger Jan 05 '18 at 20:04
  • @JohnBollinger: 6.2.6.1 5: “If the stored value of an object has such a representation and is read by an lvalue expression that does not have character type, the behavior is undefined.” 6.3.2.1 2: “Except when it is the operand of the **sizeof** operator, the **_Alignof** operator, the unary **&** operator, the **++** operator, the **--** operator, or the left operand of the **.** operator or an assignment operator, an lvalue that does not have array type is converted to the value stored in the designated object (and is no longer an lvalue); this is called *lvalue conversion*.” – Eric Postpischil Jan 05 '18 at 20:25
  • @JohnBollinger: “Read” is not explicitly defined, but you can search the standard for it to see how it is used. *E.g.*, “If the value being stored in an object is read from another object…”, and “to read or modify the value of an object” (in defining “access”). Using an lvalue other than in a `sizeof` *etc.*, reads its value. – Eric Postpischil Jan 05 '18 at 20:28
  • @EricPostpischil, the pointer value in question is not the stored value of any object until after the main function assigns it to variable `cur`. Prior to that, its use as the return value of function `test()` does not fall into any of the categories listed in 6.2.6.1/5. Have you some other basis for asserting that that use produces undefined behavior? – John Bollinger Jan 05 '18 at 20:39
  • @JohnBollinger: Reading the value from `cur` has undefined behavior, as stated previously. The fact that it had to be written to `cur` while it may have been a trap representation does not alter the fact that reading it from `cur` is covered by 6.2.6.1 5 and 6.3.2.1 2. Or, any value may have been written to `cur`, but, because it is indeterminate, it may be different when read back. (See [this answer](https://stackoverflow.com/a/17394924/298225) for information on that.) This is for C, of course. For C++, “Any other use of an invalid pointer value has implementation-defined behavior” applies. – Eric Postpischil Jan 06 '18 at 12:13

2 Answers2

3

enter image description here

This is a stack.

You put the plate on top of that stack and noticed it was at say position number 8.

You then remove the plate from the top and then put it back there a 1000000 times.

You are now asking why it is always on position number 8.

To which my answer is, why wouldn't it be there ?


Obviously this is a metaphor and a simplification of what's happening in here, to fully understand you can learn more about assembly and how function calls are executed, parameters pushed, registers used, compiler optimisations etc. but in summary what's happening with the plates stack is the answer to your question:

Your scoped variables in memory are stored in the form of a stack.

Your variable is just put and removed form the same place in memory, calling the function pushes it on the stack and ending the function scope pops it from the stack.

Drax
  • 12,682
  • 7
  • 45
  • 85
0

Use a test that has a better chance of showing different result. Call test() from different levels (function call depth) of code. Calling test() from the same level of code, or even a few different with optimizations, can result in int c occupying the same address over and over.

To avoid undefined behavior issues, this test() returns an integer.

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

intptr_t test(int a, int b) {
  int c = 0;
  c = c + a + b;
  intptr_t ptr = (intptr_t) &c;
  return ptr;
}

intptr_t foo(int a, int b) {
  // Adjust mask as needed to incur various levels of recursion
  if (a&15) return foo(a+1,b);  // Call at different levels
  return test(a, b);
}

int main() {
  intptr_t pre = test(5, 9);
  int i = 0;
  for (i = 0; i < 1000000; i++) {
    intptr_t cur = foo(i, i + 6);
    if (cur != pre) {
      printf("wrong %d %td != %td\n", i, pre, cur);
      break;
    }
  }
  puts("done");
  return 0;
}

Output

wrong 0 2673680 != 2673648
done
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256