8

Consider the following code.

#include<stdio.h>
int *abc(); // this function returns a pointer of type int

int main()
{
    int *ptr;
    ptr = abc();
    printf("%d", *ptr);
    return 0;
}

int *abc()
{
    int i = 45500, *p;
    p = &i;
    return p;
}

Output:

45500

I know according to link this type of behavior is undefined. But why i am getting correct value everytime i run the program.

Community
  • 1
  • 1
Cody
  • 2,480
  • 5
  • 31
  • 62
  • Because undefined behaviour is allowed to do that. By the way, I don't see anything wrong with this question. Upvoted. – Bathsheba Sep 07 '16 at 15:11
  • 3
    Its because your program is very simple. Try to insert a call to some other function between calls to `abc()` and `printf()` – Serge Sep 07 '16 at 15:11
  • 3
    So what? "Undefined" doesn't mean "random"... – Eugene Sh. Sep 07 '16 at 15:14
  • Add this, immediately after the call to `abc()` and before the existing `printf`: `printf("Test string %d %d %d %d\n", 1, 2, 3, 4)`. Then see what happens :) – kdopen Sep 07 '16 at 15:20
  • Call *abc()* then call *def()* and after check what *p* points to... You could make *i* static, as long as there is no reentrance issue... (e.g. threads modifying `*p` ...) – Déjà vu Sep 07 '16 at 15:34

2 Answers2

6

Every time you call abc it "marks" a region at the top of the stack as the place where it will write all of its local variables. It does that by moving the pointer that indicates where the top of stack is. That region is called the stack frame. When the function returns, it indicates that it does not want to use that region anymore by moving the stack pointer to where it was originally. As a result, if you call other functions afterwards, they will reuse that region of the stack for their own purposes. But in your case, you haven't called any other functions yet. So that region of the stack is left in the same state.

All the above explain the behavior of your code. It is not necessary that all C compilers implement functions that way and therefore you should not rely on that behavior.

redneb
  • 21,794
  • 6
  • 42
  • 54
  • 6
    This is *very* implementation specific. – Eugene Sh. Sep 07 '16 at 15:15
  • Yes, I am only explaining the behavior to satisfy his curiosity. – redneb Sep 07 '16 at 15:17
  • As an example Keil C compiler for i8051: It allocates locals in data segment by building a calling tree at link time, so stack is used only to pass control – Serge Sep 07 '16 at 15:18
  • @Serge: How does it handle recursion? – EOF Sep 07 '16 at 15:19
  • @EOF Well, it has a special keyword `recursion` (or `-ive`, I can't recall) to declare a function as a recursive one. Then it maintains an software stack to copy locals on that stack upon second entry to that function. TBH, they did a good job taking to account capabilities of that mCPU – Serge Sep 07 '16 at 15:22
  • Generally speaking, such compilers (same as with those for Microchip 8 bit ones) don't allow recursion (they detect it at link time). They will also often complain about calling the same function from background and ISRs (i.e. no such thing as re-entrant code) – kdopen Sep 07 '16 at 15:22
  • @kdopen: C *requires* recursion to be possible: C11 draft standard n1570: *6.5.2.2 Function calls 11 Recursive function calls shall be permitted, both directly and indirectly through any chain of other functions.* If the compiler doesn't allow recursion, it's not a C-compiler. – EOF Sep 07 '16 at 15:24
  • @EOF when Keil released the MCS51 comiler `C11` did not exist yet) – Serge Sep 07 '16 at 15:25
  • 1
    Which is where the spec meets reality. I've had this discussion with others. Sometimes, there is no way to create a conformant compiler for a given chip architecture. That doesn't mean an almost-compliant compiler isn't better than raw assembler. Also, those compilers are usually C90 – kdopen Sep 07 '16 at 15:26
  • @Serge: C99 draft standard n1256: *6.5.2.2 Function calls 11 Recursive function calls shall be permitted, both directly and indirectly through any chain of other functions.* This is not new. – EOF Sep 07 '16 at 15:27
  • @EOF I used that compiler in the beginning of 00's. Anyway, it is a history now. – Serge Sep 07 '16 at 15:28
  • @Serge the one I'm talking about is still available and still in use: "All the MPLAB XC compilers conform to the ANSI X3.159-1989 Standard for programming languages (with the exception of the MPLAB XC8 compiler’s inability to allow recursion, as mentioned in the footnote). This is commonly called the C89 Standard. Some features from the later standard, C99, are also supported. " – kdopen Sep 07 '16 at 15:31
  • @kdopen I doubt you would find anything significantly newer for MCS51, so that Keil's compiler is still available in a sense. At least I still have it :) – Serge Sep 07 '16 at 15:33
  • @EOF: Does the Standard specify any minimum depth that an implementation must support without UB? – supercat Sep 07 '16 at 22:24
  • @supercat: None that I'm aware of. – EOF Sep 07 '16 at 22:30
  • @EOF: Some implementations that statically allocate stacks will only run programs that can be guaranteed not to die from a stack overflow. While there are purposes for which recursion is needed, a guarantee that a program will work without stack overflow seems more useful than saying that an implementation must "try" to run a program, but can do anything it likes if it overflows an arbitrarily-small stack [the "one program" rule could be satisfied by a contrived program whose stack usage could be optimized away]. – supercat Sep 07 '16 at 22:55
  • Suggestion: "you should not rely on that behavior." -> "you should not rely on that behavior, which is undefined per the standard." – RobertS supports Monica Cellio Jun 23 '20 at 18:25
2

Well, undefined behavior is, undefined. You can never rely on UB (or on an output of a program invoking UB).

Maybe, just maybe in your environment and for your code, the memory location allocated for the local variable is not reclaimed by the OS and still accessible, but there's no guarantee that it will have the same behavior for any other platform.

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261