Volume and lifetime of local variables in C

I would like to understand the difference between the next two C programs.

First program:

void main() { int *a; { int b = 10; a=&b; } printf("%d\n", *a); } 

The second program:

 void main() { int *a; a = foo(); printf("%d\n", *a); } int* foo() { int b = 10; return &b; } 

In both cases, the address of local variable ( b ) is returned and assigned to a . I know that accessing memory a should not be available when b goes out of scope. However, when compiling the above two programs, I get the following warning only for the second program:

warning C4172: returning the address of a local variable or temporary

Why am I not getting a similar warning for the first program?

+6
source share
6 answers

As you already know that b goes out of scope in each instance, and access to this memory is illegal, I only drop my thoughts about why only one case gives a warning and the other does not.

In the second case, you return the address of a variable stored in Stack memory. Thus, the compiler detects the problem and warns you about it.

The first case, however, skips checking the compiler because the compiler sees that a valid initialized address is assigned to a . Compilers are largely dependent on the intelligence of the encoder.

Similar examples to describe your first case may be

 char temp[3] ; strcpy( temp, "abc" ) ; 

The compiler sees that temp has memory space, but depends on the intelligence of the encoder on the number of char s that they are going to copy in this memory area.

+4
source

your foo() function has undefined behavior, since it returns a pointer to the part of the stack’s memory that is no longer in use and which will be overwritten the next time the function is called or something

it is called "b goes out of scope." Of course, the memory still exists and probably has not changed yet, but this is not guaranteed.

The same applies to your first code, since region b ends with the closing bracket of the block there b .

Edit: you did not receive a warning in the first code because you did not return anything. The warning explicitly refers to return . And since the compiler can simultaneously allocate stack space for the entire function and include all subblocks, this can guarantee that the value will not be overwritten. but nevertheless this behavior is undefined.

You may receive additional warnings if you use a higher warning level.

+2
source

In the first code snippet, even if you explicitly add parentheses, the stack space you use is in the same region; there are no jumps or returns in the code, so the code still uses sequential memory addresses from the stack. Several events occur:

  • The compiler will not push extra variables onto the stack, even if you pop out a block of code.
  • You limit the visibility of variable b to this code block; which is more or less the same as if you declared it at the beginning and used it only once in the same place, but without {...}
  • The value for b is most likely stored in the register, so there is no need to print it later, but this is speculative.

For the second code fragment, a function call means a jump and a return, which means:

  • pressing the current stack pointer and context on the stack
  • push the appropriate values ​​to call the function on the stack
  • go to function code
  • execute function code
  • restore stack pointer to value before function call

Since the stack pointer was restored, everything on the stack is not lost (but still), but any operations on the stack are likely to override these values.

I think it’s easy to understand why you get a warning in only one case and that the expected behavior might be ...

0
source

Perhaps this is due to the implementation of the compiler. In the second program, the compiler can determine that the callback is a warning because the program returns a variable from scope. I think it is easy to determine using the ebp register information. But in the first program, our compiler needs to do more work to achieve it.

0
source

Your both programs cause undefined behavior. Expressions grouped in braces are called block or compound expressions. Any variable defined in a block has a scope only in this block. As soon as you leave the block area, this variable ceases to exist and illegally refers to it.

 int main(void) { int *a; { // block scope starts int b = 10; // b exists in this block only a = &b; } // block scope ends // *a dereferences memory which is no longer in scope // this invokes undefined behaviour printf("%d\n", *a); } 

Similarly, automatic variables defined in a function have a scope function. Once the function returns, the variables that are allocated on the stack are no longer available. This explains the warning you get for your second program. If you want to return a variable from a function, you should select it dynamically.

 int main(void) { int *a; a = foo(); printf("%d\n", *a); } int *foo(void) { int b = 10; // local variable // returning the address of b which no longer exists // after the function foo returns return &b; } 

In addition, the main signature must be one of the following -

 int main(void); int main(int argc, char *argv[]); 
0
source

In your first program -

The variable b is a block level variable and visibility inside this block only. But the lifetime b is the lifetime of the function, so that it lives until it leaves the main function. Since b is still highlighted, * a prints the value stored in b since the points are b.

0
source

All Articles