提问人:aTechieSmile 提问时间:5/9/2022 最后编辑:aTechieSmile 更新时间:5/10/2022 访问量:415
返回语句表达式的结果存储在内存的哪一部分?
which part of the memory does the result of the expression of the return statements gets stored in?
问:
案件是
int func(void){
int A = 10;
int B = 20;
return A+B
}
由 main 函数调用
int main(void){
int retVal = func();
return 0;
}
在函数中,两个局部变量将存储在 范围的堆栈上,但 A+B 的结果存储在哪里?func()
func()
通过引用调用,这种方法的可靠性如何?
以下功能体有什么区别
int func(void){
int A = 20;
return A;
}
和
int* func(void){
int A = 20;
return &A;
}
为什么返回值不会抛出分段错误,但返回地址会?
答:
A+B的结果存储在哪里?
这很大程度上取决于特定的架构和特定的调用召集 - 每个架构都是不同的。让我们来看看最常见的一个 - Linux 上的 x86-64(参见 https://en.wikipedia.org/wiki/X86-64 , https://en.wikipedia.org/wiki/X86_calling_conventions#cdecl , x86-64 System V ABI 在哪里记录 https://en.wikibooks.org/wiki/X86_Assembly/X86_Architecture?
您提供的函数由 gcc 编译到 godbolt 链接:
func:
push rbp
mov rbp, rsp
mov DWORD PTR [rbp-4], 10
mov DWORD PTR [rbp-8], 20
mov edx, DWORD PTR [rbp-4]
mov eax, DWORD PTR [rbp-8]
add eax, edx
pop rbp
ret
在 x86-64 上,返回值存储在寄存器中。将加法的结果放在寄存器内。设置后,函数比返回,并可以读取寄存器的内容,如果他想要得到返回值。eax
add eax, edx
eax
eax
main
eax
评论
在函数 func() 中,两个局部变量将存储到 func() 作用域的堆栈中,但 A+B 的结果存储在哪里?
取决于目标体系结构的特定调用约定,通常在寄存器中(例如在 x86 上)。eax
以下功能体有什么区别
int func(void){ int A = 20; return A; }
和
int* func(void){ int A = 20; return &A; }
在第一种情况下,你返回表达式的结果,它只是整数值;IOW,该值被写入某个寄存器或其他内存位置,由调用函数读取。A
20
20
在第二种情况下,您将返回表达式 的结果,即 中变量的地址。这样做的问题是,一旦出口不复存在,并且该内存位置可用于其他内容;指针值不再有效,并且取消引用无效指针的行为未定义。&A
A
func
func
A
鉴于您用“C”关键字标记了这一点,值得一提的是,C 早期的意图是返回值(作为整数或指针)应该适合处理器寄存器,因此没有分配内存来存储该值。
调用函数可能需要声明一个变量来存储结果,并负责该分配。从函数返回后,调用方会立即将商定的处理器寄存器值存储到它保留的内存中。当然,如果该值立即用于其他计算,则可能没有必要这样做。
当返回指针时,指针指向的内容对程序员来说是一个问题:你。正如你所发现的,如果你试图访问一个值,你只在被调用的函数中声明为局部变量,并使用指针返回,局部变量空间(函数调用堆栈)被大量重用,你的值将很快被丢弃。
当然,您可以在现代 C 和 C++ 中返回浮点值和结构,这通常需要不同的处理。通常,调用方函数必须为被调用函数保留空间,以便将这些较大的对象存储到其中。
请注意,编译器通常能够内联和优化代码以使用可用的寄存器,而不是重复使用商定的寄存器,有时甚至用一组寄存器替换小型结构。
像 godbolt 这样的工具可以让你轻松查看编译器对你的代码做了什么。
上一个:按引用调用失败
下一个:Python 更改列表项
评论
func
retVal
retVal