Frage

Suppose I have a function that declares and initializes two local variables – which by default have the storage duration auto. This function then calls a second function, to which it passes the addresses of these two local variables. Can this second function safely use these pointers?

A trivial programmatic example, to supplement that description:

#include <stdio.h>

int adder(int *a, int *b)
{
    return *a + *b;
}

int main()
{
    auto int a = 5;    // `auto' is redundant; included for clarity
    auto int b = 3;

    // adder() gets the addresses of two auto variables! is this an issue?
    int result = adder(&a, &b);
    printf("5 + 3 = %d\n", result);

    return 0;
}

This program works as expected, printing 5 + 3 = 8.

Usually, when I have questions about C, I turn to the standard, and this was no exception. Specifically, I checked ISO/IEC 9899, §6.2.4. It says there, in part:

4 An object whose identifier is declared with no linkage and without the storage-class specifier static has automatic storage duration.

5 For such an object that does not have a variable length array type, its lifetime extends from entry into the block with which it is associated until execution of that block ends in any way. (Entering an enclosed block or calling a function suspends, but does not end, execution of the current block.) If the block is entered recursively, a new instance of the object is created each time. The initial value of the object is indeterminate. If an initialization is specified for the object, it is performed each time the declaration is reached in the execution of the block; otherwise, the value becomes indeterminate each time the declaration is reached.

Reading this, I reason the following points:

  1. Variables a and b have storage duration auto, which I've made explicit using the auto keyword.

  2. Calling the adder() function corresponds to the parenthetical in clause 5, in the partial quote above. That is, entering the adder() function "suspends, but does not end," the execution of the current block (which is main()).

  3. Since the main() block is not "end[ed] in any way," storage for a and b is guaranteed. Thus, accessing them using the addresses &a and &b, even inside adder(), should be safe.

My question, then, is: am I correct in this? Or am I just getting "lucky," and accessing memory locations that, by happenstance, have not been overwritten?


P.S. I was unable to find an exact answer to this question through either Google or SO's search. If you can, mark this as a duplicate and I'll delete it.

War es hilfreich?

Lösung

Yes, it is safe and basically your assumptions are correct. The lifetime of an automatic object is from the entry in the block where it has been declared until the block terminates.

(C99, 6.2.4p5) "For such an object [...] its lifetime extends from entry into the block with which it is associated until execution of that block ends in any way.

Andere Tipps

Your reasoning is correct for your particular function call chain, and you have read and quoted the relevant portions of the standard. This is a perfectly valid use of pointers to local variables.

Where you have to be wary is if the function stores the pointer values in a structure that has a lifetime longer than its own call. Consider two functions, foo(), and bar():

int *g_ptr;

void bar (int *p) {
    g_ptr = p;
}

void foo () {
    int x = 10;
    bar(&x);
}

int main () {
    foo ();
    /* ...do something with g_ptr? */
    return 0;
}

In this case, the variable xs lifetime ends with foo() returns. However, the pointer to x has been stored in g_ptr by bar(). In this case, it was an error for foo() to pass a pointer to its local variable x to bar().

What this means is that in order to know whether or not it is valid to pass a pointer to a local variable to a function, you have to know what that function will do with it.

Those variables are allocated in the stack. As long as you do not return from the function that declared them, they remain valid.

As I'm not yet allowed to comment, I'd rather write another answer as amendment to jxh's answer above:

Please see my elaborate answer here for a similar question. This contains a real world example where the aliasing in the called function makes your code break even though it follows all the c-language rules.

Even though it is legal in the C-language I consider it as harmful to pass pointers to automatic variables in a function call. You never know (and often you don't want to know) what exactly the called function does with the passed values. When the called function establishes an alias, you get in big trouble.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top