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.