This is a sad story, how many small partners in writing C language code encountered the situation!

Question: how many uninitialized local variables are there in C?

The answer is often:

▶ Related to the compiler;

▶ Possible, but not guaranteed, initialization to 0;

▶ Undetermined.

In short, it’s all po-faced, metaphysical answers, and it’s annoying.

If someone is going on and on about compilers, C libraries, and processor architectures without giving you an actual scenario to reproduce the problem, they’re probably talking bull.

In fact, this question itself is the wrong way to ask, said all can speak 100,000 words, as long as we can determine its specific behavior in a specific scene is OK, of course, this needs to design a relatively OK experiment.

In the demonstration a behavior before the actual code, gives a knowledge, CPU not know variables, more can’t identify the name of the variable, the CPU will only from a specific memory location value or the value to a specific memory location, so when asked what is the value of a variable, must want to know the variable where the corresponding value is saved.

Take a look at the following code:

#include <stdio.h>void func1(){int a; printf("func1:%d\n", a); a = 12345; }void func2(){int b; printf("func2:%d\n", b); }void func4(){int d; printf("func3:%d\n", d); }void func3(){int c; printf("func3:%d\n", c); c = 54321; func4(); }void test_call(){func3(); }int main(int argc, char **argv){func1(); func2(); test_call(); }Copy the code

— — — — —

We have func1 ~ func4, a total of four functions, each of which has an uninitialized local variable, what are their values?

For such local variables, their values depend on:

▶ Position of the variable in the stack.

▶ Is the stack position corresponding to the variable previously stored?

As you can see, the first point marks a memory location, and the second point is the behavior of the code. That is, as long as there is code to store the location, and subsequent code does not reset the value of the location, the location will retain the value of the original store.

Verification is easy, just try it out:

[root@localhost test]# ./a.outfunc1:0func2:12345func3:0func3:0
Copy the code

— — — — — —

According to the change of function call stack frame, the local variable A of Func1 and the local variable B of func2 are obviously in the same position. When func1 is called, this is a new piece of memory (maybe a stack frame reached this position before entering main), and the value of A depends on the initial value of the offset corresponding to the page called into memory at this position. It depends on the operating system:

▶ The operating system may clear pages to zero when assigning pages to programs.

Stack allocation does not involve the C library, which obviously does not involve C library behavior, but memory allocation like malloc does.

In print, a has a value of 0, and we think the operating system has returned zero pages to the application. Func1 is then assigned 12345 and the function returns. Func2 is then called and the stack frame is reconstructed at the position where func1 has exited before, still 12345.

I don’t see a stack zero instruction following func1’s RET operation. For efficiency’s sake, there should be no such directive.

Func3 and func4 are not called on the same stack frame, so the 54321 assigned to c in func3 does not affect the value d in the stack frame of func4 above it. So the initial values of c and d remain 0.

So what’s the difference at the instruction level between initializing a local variable and not initializing a local variable?

Func1, an uninitialized local variable, is simple:

// int a; 00000000004005ad <func1>:4005ad: 55 push %rbp4005ae: 48 89 e5 mov %rsp,%rbp4005b1: 48 83 ec 10 sub $0x10,%rsp4005b5: 8b 45 fc mov -0x4(%rbp),%eax4005b8: 89 c6 mov %eax,%esi4005ba: bf 90 07 40 00 mov $0x400790,%edi4005bf: b8 00 00 00 00 mov $0x0,%eax4005c4: e8 b7 fe ff ff callq 400480 <printf@plt>4005c9: c7 45 fc 39 30 00 00 movl $0x3039,-0x4(%rbp)4005d0: c9 leaveq4005d1: c3 retqCopy the code

— — — — — —

Initialize the local variable a to 2222:

// int a = 2222; 00000000004005ad <func1>:4005ad: 55 push %rbp4005ae: 48 89 e5 mov %rsp,%rbp4005b1: 48 83 ec 10 sub $0x10,%rsp4005b5: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp)4005bc: 8b 45 fc mov -0x4(%rbp),%eax4005bf: 89 c6 mov %eax,%esi4005c1: bf 90 07 40 00 mov $0x400790,%edi4005c6: b8 00 00 00 00 mov $0x0,%eax4005cb: e8 b0 fe ff ff callq 400480 <printf@plt>4005d0: c7 45 fc 39 30 00 00 movl $0x3039,-0x4(%rbp)4005d7: c9 leaveq4005d8: c3 retqCopy the code

— — — — — —

Only one instruction was missing:

4005b5: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp)

— — — — — —

The initialization is done by actual instructions.

To sum up:

When the function returns a pop out of the current stack frame, it does not clean up the data it left behind in the stack frame. When the next function call reuses the memory of the stack frame, the uninitialized local variable will be affected by the legacy data and become indeterminate.

So remember to initialize your local variables.

— — — — — —

You have gained a new understanding of programming languages

If you like this article, give it a thumbs-up

If you want to learn programming, xiaobian recommended a C language /C++ programming Q group: 966268043

[Click to enter]!

! [](https://upload-images.jianshu.io/upload_images/24175598-eb2801bb4cbb7d80.gif? imageMogr2/auto-orient/strip)

An active, high-powered, high-level programming learning hall; The introduction of programming is only a side, the improvement of thinking is valuable!

** Involved: ** Introduction to programming, game programming, network programming, Windows programming, Linux programming, Qt interface development, hacking and so on……