user1150105
user1150105

Reputation:

Is 'goto' smart for correct working with stack variables in C (not C++)

(Sorry for bad English.)

Question 1.

void foo(void)
{
    goto inside;
    for (;;) {
        int stack_var = 42;
inside:
        ...
    }
}

Will be a place in stack allocated for the stack_var when I goto the inside label? I.e. can I correctly use the stack_var variable within ...?

Question 2.

void foo(void)
{
    for (;;) {
        int stack_var = 42;
        ...
        goto outside;
    }
outside:
    ...
}

Will be a place in stack of the stack_var deallocated when I goto the outside label? E.g. is it correct to do return within ...?

In other words, is goto smart for correct working with stack variables (automatic (de)allocation when I walk through blocks), or it's just a stupid jump?

Upvotes: 11

Views: 452

Answers (2)

Pascal Cuoq
Pascal Cuoq

Reputation: 80325

Question 1:

can I correctly use the stack_var variable within ...?

The code in ... can write to stack_var. However, this variable is uninitialized because the execution flow jumped over the initialization, so the code should not read from it without having written to it first.

From the C99 standard, 6.8:3

The initializers of objects that have automatic storage duration […] are evaluated and the values are stored in the objects (including storing an indeterminate value in objects without an initializer) each time the declaration is reached in the order of execution

My compiler compiles the function below to a piece of assembly that sometimes returns the uninitialized contents of x:

int f(int c){
  if (c) goto L;
  int x = 42;
 L:
  return x;
}

    cmpl    $0, %eax
    jne LBB1_2
    movl    $42, -16(%rbp)
LBB1_2:
    movl    -16(%rbp), %eax
...
    popq    %rbp
    ret

Question 2:

Will be a place in stack of the stack_var deallocated when I goto the outside label?

Yes, you can expect the memory reserved for stack_var to be reclaimed as soon as the variable goes out of scope.

Upvotes: 10

There are two different issues:

  • lexical scoping of variables inside C code. A C variable only makes sense inside the block in which it is declared. You could imagine that the compiler is renaming variables to unique names, which have sense only inside the scope block.

  • call frames in the generated code. A good optimizing compiler usually allocate the call frame of the current function on the machine class stack at the beginning of the function. A given location in that call frame, called a slot can (and usually is) reused by the compiler for several local variables (or other purposes).

And a local variable can be kept in a register only (without any slot in the call frame), and that register will obviously be reused for various purposes.

You are probably hurting undefined behavior for your first case. After the goto inside the stack_var is uninitialized.

I suggest you to compile with gcc -Wall and to improve the code till no warnings are given.

Upvotes: 2

Related Questions