return 语句的表达式结果存储在内存的哪一部分?

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
    }

被主函数调用

int main(void){
    int retVal = func();
    return 0;
}

在函数func()中,两个局部变量将被存储到func()作用域的堆栈中,但是A+B的结果存储在哪里?

通过引用调用,这种方法的可靠性如何?

下面的函数体有什么区别

int func(void){
    int A = 20;
    return A;
}

int* func(void){
    int A = 20;
    return &A;
}

为什么返回值不会抛出段错误,但返回地址会抛出?

where does the result of A+B stored?

强烈地取决于特定的体系结构和特定的调用约定——每个体系结构都是不同的。让我们检查最常见的一个 - Linux 上的 x86-64(参见 https://en.wikipedia.org/wiki/X86-64 , https://en.wikipedia.org/wiki/X86_calling_conventions#cdecl , Where is the x86-64 System V ABI documented? , https://en.wikibooks.org/wiki/X86_Assembly/X86_Architecture)。

你提供的函数被gcc编译为godbolt link:

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 上,return 值存储在 eax 寄存器中。 add eax, edx 将加法结果放入 eax 寄存器。设置eax后,函数比returns,main如果想得到return的值,可以读取eax寄存器的内容。

in the function func() two local variables will be stored onto the stack for the scope of func() but where does the result of A+B stored?

取决于目标体系结构的特定调用约定,通常在寄存器中(例如 x86 上的 eax)。

what is the difference between following function bodies

int func(void){
    int A = 20;
    return A;
}

and

int* func(void){
    int A = 20;
    return &A;
}

在第一种情况下,您将返回 表达式 A 的结果,它只是整数值 20; IOW,值 20 被写入某个寄存器或其他内存位置,由调用函数读取。

在第二种情况下,您将返回表达式 &A 的结果,即 [=18= 中变量 A 地址 ].这样做的问题是,一旦 func 退出,A 将不复存在,并且该内存位置可用于其他用途;指针值不再 有效 ,取消引用无效指针的行为未定义。

鉴于您用“C”关键字标记了它,值得一提的是 C 早期的意图是 return 值,作为整数或指针,应该适合处理器寄存器,因此没有分配内存来存储该值。

调用函数可能需要声明一个变量来存储结果,它负责分配。在函数 return 上,调用者立即将商定的处理器寄存器值存储到它保留的内存中。当然,如果该值立即用于某些其他计算,则可能没有必要。

当return指向一个指针时,指针指向的是程序员的问题:你。正如您所发现的,如果您尝试访问一个值,您只在被调用函数中声明为局部变量并使用指针 returned,则局部变量 space - 函数调用堆栈 - 非常重要重复使用,你的价值将很快被废弃。

当然,您可以 return 现代 C 和 C++ 中的浮点值和结构,这通常需要不同的处理方式。通常调用函数必须为被调用函数保留space来存储这些更大的对象。

请注意,编译器通常能够内联和优化代码以使用可用的寄存器,而不是重复使用约定的寄存器,有时甚至用一组寄存器替换小结构。

godbolt 等工具可以让您轻松查看编译器对您的代码做了什么。