开发者

How does temporary storage work in C when a function returns?

I know C pretty well, however I'm confused of how temporary storage works.

Like when a function returns, all the allocation happened inside that function is freed (from the stack or however the implementation decides to do this).

For example:

void f() {
    int a = 5;
} // a's value doesn开发者_Go百科't exist anymore 

However we can use the return keyword to transfer some data to the outside world:

int f() {
    int a = 5;
    return a;
} // a's value exists because it's transfered to the outside world

Please stop me if any of this is wrong.

Now here's the weird thing, when you do this with arrays, it doesn't work.

int []f() {
    int a[1] = {5};
    return a;
} // a's value doesn't exist. WHY?

I know arrays are only accessible by pointers, and you can't pass arrays around like another data structure without using pointers. Is this the reason you can't return arrays and use them in the outside world? Because they're only accessible by pointers?

I know I could be using dynamic allocation to keep the data to the outside world, but my question is about temporary allocation.

Thanks!


When you return something, its value is copied. a does not exist outside the function in your second example; it's value does. (It exists as an rvalue.)

In your last example, you implicitly convert the array a to an int*, and that copy is returned. a's lifetime ends, and you're pointing at garbage.

No variable lives outside its scope, ever.


In the first example the data is copied and returned to the calling function, however the second returns a pointer so the pointer is copied and returned, however the data that is pointed to is cleaned up.


In implementations of C I use (primarily for embedded 8/16-bit microcontrollers), space is allocated for the return value in the stack when the function is called.

Before calling the function, assume the stack is this (the lines could represent various lengths, but are all fixed):

[whatever]
...

When the routine is called (e.g. sometype myFunc(arg1,arg2)), C throws the parameters for the function (arguments and space for the return value, which are all of fixed length) on to the stack, followed by the return address to continue code execution from, and possibly backs up some processor registers.

[myFunc local variables...]
[return address after myFunc is done]
[myFunc argument 1]
[myFunc argument 2]
[myFunc return value]
[whatever]
...

By the time the function fully completes and returns to the code it was called from, all of it's variables have been deallocated off the stack (they might still be there in theory, but there is no guarantee)

In any case, in order to return the array, you would need to allocate space for it somewhere else, then return the address to the 0th element.

Some compilers will store return values in temporary registers of the processor rather than using the stack, but it's rare (only seen it on some AVR compilers).


When you attempt to return a locally allocated array like that, the calling function gets a pointer to where the array used to live on the stack. This can make for some spectacularly gruesome crashes, when later on, something else writes to the array, and clobbers a stack frame .. which may not manifest itself until much later, if the corrupted frame is deep in the calling sequence. The maddening this with debugging this type of error is that real error (returning a local array) can make some other, absolutely perfect function blow up.


You still return a memory address, you can try to check its value, but the contents its pointing are not valid beyond the scope of function,so dont confuse value with reference.


int []f() {
    int a[1] = {5};
    return a;
} // a's value doesn't exist. WHY?

First, the compiler wouldn't know what size of array to return. I just got syntax errors when I used your code, but with a typedef I was able to get an error that said that functions can't return arrays, which I knew.

typedef int ia[1];
ia h(void) {
    ia a = 5;
    return a;
}

Secondly, you can't do that anyway. You also can't do

int a[1] = {4};
int b[1];
b = a; // Here both a and b are interpreted as pointer literals or pointer arithmatic

While you don't write it out like that, and the compiler really wouldn't even have to generate any code for it this operation would have to happen semantically for this to be possible so that a new variable name could be used to refer the value that was returned by the function. If you enclosed it in a struct then the compiler would be just fine with copying the data.

Also, outside of the declaration and sizeof statements (and possibly typeof operations if the compiler has that extension) whenever an array name appears in code it is thought of by the compiler as either a pointer literal or as a chunk of pointer arithmetic that results in a pointer. This means that the return statement would end looking like you were returning the wrong type -- a pointer rather than an array.

If you want to know why this can't be done -- it just can't. A compiler could implicitly think about the array as though it were in a struct and make it happen, but that's just not how the C standard says it is to be done.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜