Reputation: 2625
I have some simple C++ code:
#include <iostream>
int main(){
{
int a = 10;
tag:
std::cout << a << std::endl;
}
goto tag;
return 0;
}
Now I know it is not a good idea to use goto
and if I jump with goto
to some other scope, I will get compile error. I have tried this and it is naturally giving me a compile error which is obvious. But my question is whether there is any way for which this may get into some infinite loop
I am asking this question because of this question
Upvotes: 1
Views: 329
Reputation: 754030
I note that the code in the question is C++ code and not C code. However, the question is dual-tagged with C and C++, which is irksome since the rules for C and C++ are different.
The C++ code in the question should not compile. Analogous code written in C should compile, but the net result is an infinite loop.
In ISO/IEC 14882:2011 (the C++11 standard; I don't have an official copy of the 2014 standard to report on), it says:
6.6.4 The goto statement [stmt.goto]
¶1 The
goto
statement unconditionally transfers control to the statement labeled by the identifier. The identifier shall be a label (6.1) located in the current function.6.7 Declaration statement [stmt.dcl]
¶1 A declaration statement introduces one or more new identifiers into a block; it has the form declaration-statement: block-declaration If an identifier introduced by a declaration was previously declared in an outer block, the outer declaration is hidden for the remainder of the block, after which it resumes its force.
¶2 Variables with automatic storage duration (3.7.3) are initialized each time their declaration-statement is executed. Variables with automatic storage duration declared in the block are destroyed on exit from the block (6.6).
¶3 It is possible to transfer into a block, but not in a way that bypasses declarations with initialization. A program that jumps87 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).
87) The transfer from the condition of a switch statement to a case label is considered a jump in this respect.
Although a plain int
is a scalar type, the jump bypasses the initialization and so is not allowed.
In ISO/IEC 9899:2011 (the C11 standard), it says:
6.8.6.1 The
goto
statementConstraints
¶1 The identifier in agoto
statement shall name a label located somewhere in the enclosing function. Agoto
statement shall not jump from outside the scope of an identifier having a variably modified type to inside the scope of that identifier.Semantics
¶2 A goto statement causes an unconditional jump to the statement prefixed by the named label in the enclosing function.
Note that constraint violations require a diagnostic. Violations of rules in semantics sections do not require a diagnostic.
And in Annex I (Common Warnings), which is an informative annex and not a normative one, it says:
— A block with initialization of an object that has automatic storage duration is jumped into (6.2.4).
And
6.2.4 Storage durations of objects
¶5 An object whose identifier is declared with no linkage and without the storage-class specifier
static
has automatic storage duration, as do some compound literals. The result of attempting to indirectly access an object with automatic storage duration from a thread other than the one with which the object is associated is implementation-defined.¶6 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 or compound literal is reached in the execution of the block; otherwise, the value becomes indeterminate each time the declaration is reached.
¶7 For such an object that does have a variable length array type, its lifetime extends from the declaration of the object until execution of the program leaves the scope of the declaration.35) If the scope is entered recursively, a new instance of the object is created each time. The initial value of the object is indeterminate.
35) Leaving the innermost block containing the declaration, or jumping to a point in that block or an embedded block prior to the declaration, leaves the scope of the declaration.
Note that there is no variably modified type (no VLA or variable length array) in the code in the question. Standard C++ does not support the concept of VLAs (though the GNU C++ compiler does allow them as an extension).
Code (goto1.c
):
#include <stdio.h>
int main(void)
{
{
int a = 10;
tag:
printf("%d\n", a);
}
goto tag;
return 0;
}
Sample compilation:
$ gcc -std=c11 -O3 -g -Wall -Wextra -Werror goto1.c -o goto1
$
Those are fairly stringent warning options, and GCC utters not a peep — which is permissible behaviour given what the C standard says.
Upvotes: 5
Reputation: 114330
As the first comment to the question you mention says, the behavior is undefined. That basically means every compiler is free to interpret your code however it wants. Clearly, your compiler sees the problem and throws an error, while a different compiler may allow the code to compile, especially if it's internal representation of scope allows the loop to happen.
Upvotes: 0