I have heard about the following scenario right when I started programming in C.
当我开始用C语言编程时,我听说过以下场景。
"Trying to access from outside, a functions local variable will result in error (or garbage value). Since the stack gets cleared off when we return from the function"
“尝试从外部访问,函数局部变量将导致错误(或垃圾值)。因为当我们从函数返回时堆栈被清除”
But my below code sample prints a value of 50. I am compiling the code with latest GCC compiler.
但我的下面的代码示例打印值为50.我正在使用最新的GCC编译器编译代码。
#include <stdio.h>
int * left();
int main()
{
int *p=left();
printf("%d\n",*p);
return 0;
}
int * left()
{
int i=50;
return &i;
}
Enlight me on this issue.
在这个问题上欢迎我。
Can I know the behaviour in C++ ?? Is it similar to c ..
我能知道C ++中的行为吗?它类似于c ..
8 个解决方案
#1
7
Modify it to add a second call to printf
and you'll see a different value from the first time. Compile it with optimizations turned on and you'll see another set of values. Do anything with the value and you're stepping into undefined territory, which means that the compiler is free to summon demons through your nasal passages.
修改它以添加对printf的第二次调用,您将从第一次看到不同的值。在启用优化的情况下编译它,您将看到另一组值。做任何有价值的东西,你进入未定义的领域,这意味着编译器可以通过你的鼻段*地召唤恶魔。
On my system, I see 50
and then 0
; with optimizations I see 0
and then 32767
.
在我的系统上,我看到50然后是0;通过优化,我看到0然后是32767。
If you make the local variable static
, then you can return its address since it becomes just like a global (but remember that there is only one instance of it).
如果你将局部变量设为静态,那么你可以返回它的地址,因为它变得像一个全局变量(但请记住它只有一个实例)。
When a function returns, the local storage it was using on the stack is now considered "unused" by the program, since the stack doesn't go that high anymore. Typically, though, the values are still there, since there's no urgent need to clear them. The memory is also still owned by the program, since there's no sense in returning memory to the operating system a few bytes at a time. So for your specific example, under the circumstances in which you compiled it, the memory pointed to still contains the value 50
. Officially, though, the value of *p
is indeterminate, and attempts to use it result in undefined behavior.
当一个函数返回时,它在堆栈上使用的本地存储现在被程序视为“未使用”,因为堆栈不再那么高了。但通常情况下,值仍然存在,因为没有迫切需要清除它们。内存也仍然由程序拥有,因为将内存一次几个字节返回给操作系统是没有意义的。因此,对于您的具体示例,在您编译它的情况下,指向的内存仍然包含值50.但是,正式地说,* p的值是不确定的,并且尝试使用它会导致未定义的行为。
One existential crisis of the C language is how on the one hand, it says nothing about the stack and the various bits of hexadecimal sludge that make up a running process; on the other hand, it's necessary to understand those in order to protect yourself from crashes, buffer overflows, and undefined behavior. Just remember that you're lucky that GCC gives a warning for this.
C语言的一个存在主义危机是,一方面它没有说明堆栈和构成运行过程的各种十六进制污泥;另一方面,有必要了解这些以保护自己免受崩溃,缓冲区溢出和未定义的行为。请记住,你很幸运GCC会对此发出警告。
#2
12
The variable 'i' is created on the stack and when the function 'left' returns, the stack is cleared. When I say cleared, it means the address used by variable 'i' is marked free for reuse. Till some other portion of code uses the same address, the value will remain unmodified. In your case, it is plain luck that gives you desired results. If you call few more functions after call to 'left', I am fairly certain you will get wrong results.
变量'i'在堆栈上创建,当函数'left'返回时,堆栈被清除。当我说清除时,这意味着变量'i'使用的地址被标记为可以重复使用。直到其他部分代码使用相同的地址,该值将保持不变。在你的情况下,这是一个幸运的,可以给你想要的结果。如果你在打电话给'left'之后再调用几个函数,我相当肯定你会得到错误的结果。
#3
6
The behavior according to the C standard is undefined not garbage values. So it's possible, and occasionally likely, that the value will remain unchanged. This is not guaranteed by any means.
根据C标准的行为是未定义的而不是垃圾值。因此,有可能,偶尔也可能,价值将保持不变。无论如何都无法保证这一点。
This is working by luck / chance / accident and nothing else. Don't rely on this behavior because it will come back to bite you.
这是运气/机会/事故,没有别的。不要依赖这种行为,因为它会回来咬你。
#4
3
Look at this modified example, where it shows clearly if something goes in between:
看看这个修改过的例子,它清楚地显示了两者之间是否有什么:
int *p=left();
// right here
printf("%d\n",*p);
You get a corrupted stack easily. The idea is that you don't own that place, someone else could use it!
你很容易得到一个损坏的堆栈。这个想法是你不拥有那个地方,别人可以使用它!
int main()
{
int *p=left();
right(); // Look here!
printf("%d\n",*p); // prints -50 instead of 50
return 0;
}
...
int * right()
{
int i=-50;
return &i;
}
#5
2
You are referring to an object beyond its lifetime (the scope of left()
). That results in undefined behaviour - I'd guess that you still get 50 because nothing has overwritten the area where i
was yet.
您指的是超出其生命周期的对象(left()的范围)。这导致了不确定的行为 - 我猜你仍然得到50,因为没有任何东西覆盖了我还没有的区域。
#6
2
It works by accident. Memory location pointed by p
still contains integer value 50 when printf()
is called. But call to any function inside main()
between left()
and printf()
would overwrite it.
它偶然起作用。当调用printf()时,p指向的内存位置仍包含整数值50。但是调用left()和printf()之间的main()内的任何函数都会覆盖它。
For example, I don't know what would happen in your implementation if you changed your printf()
call to:
例如,如果您将printf()调用更改为:我不知道您的实现会发生什么:
printf("abs(%d) = %d ???\n", *p, abs(*p));
Don't do it!
不要这样做!
#7
2
As far as the C standard is concerned, the value is undefined.
就C标准而言,该值是未定义的。
Practically, as long as nothing is pushed to the stack before the returned value is referenced, it works, but the next time a function is called the return address and new stack frame are pushed to the stack and may overwrite the referenced value.
实际上,只要在引用返回值之前没有任何东西被推送到堆栈,它就可以工作,但是下次调用函数时,返回地址和新堆栈帧被推送到堆栈并可能覆盖引用的值。
This would not be considered acceptable coding (because of the undefined nature).
这不被认为是可接受的编码(因为未定义的性质)。
#8
1
Undefined behavior. i
is destroyed upon leaving left()
. You have an address to garbage in p
. The compiler hasn't destroyed i
by luck, yet.
未定义的行为。我离开左边时被摧毁()。你有一个垃圾的地址在p。编译器还没有通过运气摧毁我。
#1
7
Modify it to add a second call to printf
and you'll see a different value from the first time. Compile it with optimizations turned on and you'll see another set of values. Do anything with the value and you're stepping into undefined territory, which means that the compiler is free to summon demons through your nasal passages.
修改它以添加对printf的第二次调用,您将从第一次看到不同的值。在启用优化的情况下编译它,您将看到另一组值。做任何有价值的东西,你进入未定义的领域,这意味着编译器可以通过你的鼻段*地召唤恶魔。
On my system, I see 50
and then 0
; with optimizations I see 0
and then 32767
.
在我的系统上,我看到50然后是0;通过优化,我看到0然后是32767。
If you make the local variable static
, then you can return its address since it becomes just like a global (but remember that there is only one instance of it).
如果你将局部变量设为静态,那么你可以返回它的地址,因为它变得像一个全局变量(但请记住它只有一个实例)。
When a function returns, the local storage it was using on the stack is now considered "unused" by the program, since the stack doesn't go that high anymore. Typically, though, the values are still there, since there's no urgent need to clear them. The memory is also still owned by the program, since there's no sense in returning memory to the operating system a few bytes at a time. So for your specific example, under the circumstances in which you compiled it, the memory pointed to still contains the value 50
. Officially, though, the value of *p
is indeterminate, and attempts to use it result in undefined behavior.
当一个函数返回时,它在堆栈上使用的本地存储现在被程序视为“未使用”,因为堆栈不再那么高了。但通常情况下,值仍然存在,因为没有迫切需要清除它们。内存也仍然由程序拥有,因为将内存一次几个字节返回给操作系统是没有意义的。因此,对于您的具体示例,在您编译它的情况下,指向的内存仍然包含值50.但是,正式地说,* p的值是不确定的,并且尝试使用它会导致未定义的行为。
One existential crisis of the C language is how on the one hand, it says nothing about the stack and the various bits of hexadecimal sludge that make up a running process; on the other hand, it's necessary to understand those in order to protect yourself from crashes, buffer overflows, and undefined behavior. Just remember that you're lucky that GCC gives a warning for this.
C语言的一个存在主义危机是,一方面它没有说明堆栈和构成运行过程的各种十六进制污泥;另一方面,有必要了解这些以保护自己免受崩溃,缓冲区溢出和未定义的行为。请记住,你很幸运GCC会对此发出警告。
#2
12
The variable 'i' is created on the stack and when the function 'left' returns, the stack is cleared. When I say cleared, it means the address used by variable 'i' is marked free for reuse. Till some other portion of code uses the same address, the value will remain unmodified. In your case, it is plain luck that gives you desired results. If you call few more functions after call to 'left', I am fairly certain you will get wrong results.
变量'i'在堆栈上创建,当函数'left'返回时,堆栈被清除。当我说清除时,这意味着变量'i'使用的地址被标记为可以重复使用。直到其他部分代码使用相同的地址,该值将保持不变。在你的情况下,这是一个幸运的,可以给你想要的结果。如果你在打电话给'left'之后再调用几个函数,我相当肯定你会得到错误的结果。
#3
6
The behavior according to the C standard is undefined not garbage values. So it's possible, and occasionally likely, that the value will remain unchanged. This is not guaranteed by any means.
根据C标准的行为是未定义的而不是垃圾值。因此,有可能,偶尔也可能,价值将保持不变。无论如何都无法保证这一点。
This is working by luck / chance / accident and nothing else. Don't rely on this behavior because it will come back to bite you.
这是运气/机会/事故,没有别的。不要依赖这种行为,因为它会回来咬你。
#4
3
Look at this modified example, where it shows clearly if something goes in between:
看看这个修改过的例子,它清楚地显示了两者之间是否有什么:
int *p=left();
// right here
printf("%d\n",*p);
You get a corrupted stack easily. The idea is that you don't own that place, someone else could use it!
你很容易得到一个损坏的堆栈。这个想法是你不拥有那个地方,别人可以使用它!
int main()
{
int *p=left();
right(); // Look here!
printf("%d\n",*p); // prints -50 instead of 50
return 0;
}
...
int * right()
{
int i=-50;
return &i;
}
#5
2
You are referring to an object beyond its lifetime (the scope of left()
). That results in undefined behaviour - I'd guess that you still get 50 because nothing has overwritten the area where i
was yet.
您指的是超出其生命周期的对象(left()的范围)。这导致了不确定的行为 - 我猜你仍然得到50,因为没有任何东西覆盖了我还没有的区域。
#6
2
It works by accident. Memory location pointed by p
still contains integer value 50 when printf()
is called. But call to any function inside main()
between left()
and printf()
would overwrite it.
它偶然起作用。当调用printf()时,p指向的内存位置仍包含整数值50。但是调用left()和printf()之间的main()内的任何函数都会覆盖它。
For example, I don't know what would happen in your implementation if you changed your printf()
call to:
例如,如果您将printf()调用更改为:我不知道您的实现会发生什么:
printf("abs(%d) = %d ???\n", *p, abs(*p));
Don't do it!
不要这样做!
#7
2
As far as the C standard is concerned, the value is undefined.
就C标准而言,该值是未定义的。
Practically, as long as nothing is pushed to the stack before the returned value is referenced, it works, but the next time a function is called the return address and new stack frame are pushed to the stack and may overwrite the referenced value.
实际上,只要在引用返回值之前没有任何东西被推送到堆栈,它就可以工作,但是下次调用函数时,返回地址和新堆栈帧被推送到堆栈并可能覆盖引用的值。
This would not be considered acceptable coding (because of the undefined nature).
这不被认为是可接受的编码(因为未定义的性质)。
#8
1
Undefined behavior. i
is destroyed upon leaving left()
. You have an address to garbage in p
. The compiler hasn't destroyed i
by luck, yet.
未定义的行为。我离开左边时被摧毁()。你有一个垃圾的地址在p。编译器还没有通过运气摧毁我。