Home > Enterprise >  which part of the memory does the result of the expression of the return statements gets stored in?
which part of the memory does the result of the expression of the return statements gets stored in?

Time:05-10

the case is

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

which is being called by the main function

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

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?

and over the call by reference, how reliable this method is?

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;
}

why returning the values does not throw the error of the segmentation fault but returning the address do?

CodePudding user response:

where does the result of A B stored?

This strongly depends on specific architecture and specific calling convension - every architecture is different. Let's inspect the most common one - x86-64 on Linux (see 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 ).

The function you presented is compiled by gcc to 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

On x86-64 the return value is stored inside eax register. The add eax, edx puts the result of the addition inside eax register. After setting eax, the function than returns, and main can read the content of eax register if he wants to get the return value.

CodePudding user response:

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?

Depends on the specific calling convention for the target architecture, usually in a register (such eax on x86).

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;
}

In the first case you are returning the result of the expression A, which is simply the integer value 20; IOW, the value 20 is written to some register or other memory location, which is read by the calling function.

In the second case you are returning the result of the expression &A, which is the address of the variable A in func. The problem with this is that once func exits A ceases to exist and that memory location becomes available for something else to use; the pointer value is no longer valid, and the behavior on dereferencing an invalid pointer is undefined.

CodePudding user response:

Given that you tagged this with the "C" keyword, it is worth saying that the intent in the early days of C was that the return value, as an integer or a pointer, should fit in a processor register, so no memory is allocated to storing the value.

The calling function may need to declare a variable to store the result into, and it is responsible for that allocation. Immediately on return from the function the caller will stash that agreed processor register value into the memory it has reserved. Of course, that may not be necessary if the value is used immediately for some other calculation.

When returning a pointer, what the pointer points to is a problem for the programmer: you. As you have found, if you try to access a value you only declared as a local variable in the called function and returned using a pointer, the local variable space - the function call stack - is heavily reused, and your value will quickly be junked.

Of course, you can return floating point values and structs in modern C and C , which often needs different handling. Usually the caller function has to reserve space for the called function to store these larger objects into.

Note that the compilers are often able to inline and optimise code to use available registers, rather than repeatedly using the agreed registers, and sometimes even replace small structures with a set of registers.

Tools like godbolt can let you easily see what the compiler has done to your code.

  • Related