33

Suppose these code compiled in g++:

#include <stdlib.h>

int main() {
    int a =0;

    goto exit;

    int *b = NULL;

exit:
    return 0;
}

g++ will throw errors:

goto_test.c:10:1: error: jump to label ‘exit’ [-fpermissive]
goto_test.c:6:10: error:   from here [-fpermissive]
goto_test.c:8:10: error:   crosses initialization of ‘int* b’

It seems like that the goto can not cross pointer definition, but gcc compiles them ok, nothing complained.

After fixed the error, we must declare all the pointers before any of the goto statement, that is to say you must declare these pointers even though you do not need them at the present (and violation with some principles).

What the origin design consideration that g++ forbidden the useful tail-goto statement?


Update:

goto can cross variable (any type of variable, not limited to pointer) declaration, but except those that got a initialize value. If we remove the NULL assignment above, g++ keep silent now. So if you want to declare variables that between goto-cross-area, do not initialize them (and still violate some principles).

coanor
  • 3,746
  • 4
  • 50
  • 67
  • Is this supposed to be a C question or a C++ question? Your files are named `.c`, but you are compiling with `g++`, which forces C++ and generates C++-specific errors. The error in question is C++-specific. – AnT stands with Russia Jan 29 '19 at 20:15

2 Answers2

44

Goto can't skip over initializations of variables, because the respective objects would not exist after the jump, since lifetime of object with non-trivial initialization starts when that initialization is executed:

C++11 §3.8/1:

[…] The lifetime of an object of type T begins when:

  • storage with the proper alignment and size for type T is obtained, and

  • if the object has non-trivial initialization, its initialization is complete.

C++11 §6.7/3:

It is possible to transfer into a block, but not in a way that bypasses declarations with initialization. A program that jumps from a point where a variable with automatic storage duration is not in scope to a point where it is in scope is ill-formed unless the variable has scalar type, class type with a trivial default constructor and a trivial destructor, a cv-qualified version of one of these types, or an array of one of the preceding types and is declared without an initializer (8.5).

Since the error mentions [-fpermissive], you can turn it to warning by specifying that compiler flag. This indicates two things. That it used to be allowed (the variable would exist, but be uninitialized after the jump) and that gcc developers believe the specification forbids it.

The compiler only checks whether the variable should be initialized, not whether it's used, otherwise the results would be rather inconsistent. But if you don't need the variable anymore, you can end it's lifetime yourself, making the "tail-goto" viable:

int main() {
    int a =0;
    goto exit;
    {
        int *b = NULL;
    }
exit:
    return 0;
}

is perfectly valid.

On a side-note, the file has extension .c, which suggests it is C and not C++. If you compile it with gcc instead of g++, the original version should compile, because C does not have that restriction (it only has the restriction for variable-length arrays—which don't exist in C++ at all).

Jan Hudec
  • 73,652
  • 13
  • 125
  • 172
  • True, but your comment implies some distinction between "variables" and "objects", which does not really exist in C++. All variables are objects in C++. – AnT stands with Russia Jan 29 '19 at 19:50
  • You completely misinterpreted your quote. It says "A goto statement is not allowed to jump past any declarations of objects **with variably modified types**." The last part is the key here. In C you can jump over **any** declarations (!), even when they are initialized (!!), but as long as they are not for **variably modified types**. I briefly mention this distinction here (https://stackoverflow.com/questions/22530363/whats-the-point-of-vla-anyway/54163435#54163435) – AnT stands with Russia Jan 29 '19 at 19:58
  • @AnT, hm, you are right. Then why does GCC consider the code invalid? Gcc decides language from the extension and the code clearly had extension of `.c` and thus should be compiled as C. And in C, it should be legal... – Jan Hudec Jan 29 '19 at 20:06
  • `g++` always compiles as C++, regardless of the extension. Extension-based language detection is done by `gcc` executable, but not by `g++`. So, this question is probably C++, not C. Although it is not clear why the OP named their files as `.c`. – AnT stands with Russia Jan 29 '19 at 20:13
5

There is an easy work-around for those primitive types like int:

 // ---  original form, subject to cross initialization error.  ---
 // int foo = 0;

 // ---  work-around form: no more cross initialization error.  ---
 int foo;  foo = 0;
Robin Hsu
  • 4,164
  • 3
  • 20
  • 37