Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Goto prior to a variable definition - what happens with its value?

Here is some question I wondered about. Given the following code, can we be certain about its output?

void f() {
  int i = 0; 
  z: if(i == 1) goto x; else goto u; 
  int a; 
  x: if(a == 10) goto y; 
  u: a = 10; i = 1; goto z; 
  y: std::cout << "finished: " << a; 
}

Is this guaranteed to output finished: 10 according to the C++ Standard? Or can the compiler occupy the register that a is stored into, when goto to a place prior to a?

like image 751
Johannes Schaub - litb Avatar asked Jul 22 '11 14:07

Johannes Schaub - litb


People also ask

What happens when a variable value type data goes out of its scope?

Nothing physical happens. A typical implementation will allocate enough space in the program stack to store all variables at the deepest level of block nesting in the current function.

What does a goto statement do?

The goto statement can be used to alter the normal flow of control in a program. This statement causes the program to jump to a specified label.

Is goto a variable?

Short answer: no.

Which statement is the true for goto statement?

Statement 1: Goto statement allows an unconditional transfer of control.


2 Answers

Note: Read the comments to this one first. Johannes more or less shot down my whole argument with one well-placed standard quote. ;-)


I do not have the C++ standard available, so I have to extrapolate from the C standard.

Surprisingly enough (for me), chapter 6.2.1 Scopes of identifiers says nothing about the scope of an identifier starting at the point of its declaration (as I would have guessed). int a, in your example, has block scope, which "terminates at the end of the associated block", and that is all that is said about it. chapter 6.8.6.1 The goto statement says that "a goto statement shall not jump from outside the scope of an identifier having a variably modified type to inside the scope of that identifier" - but since your gotos jump around only within the block (and, thus, the scope of int a, that seems to be OK as far as ISO/IEC 9899:1999 is concerned.

I'm quite surprised about this...

Edit #1: A quick google later I got my hands on the C++0x final draft. The relevant statement, I think, is this here (6.7 Declaration statement, highlighting mine):

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.

I think your code is OK by the standard's standards. But butt-ugly, mind you. ;-)

Edit #2: Reading your comment about the possible destruction of int a due to the jump backwards, I found this (6.6 Jump statements, highlighting mine):

Transfer out of a loop, out of a block, or back past an initialized variable with automatic storage duration involves the destruction of objects with automatic storage duration that are in scope at the point transferred from but not at the point transferred to.

One, int a is not "initialized", and it is not an object if I understand the standard terminology correctly.

like image 163
DevSolar Avatar answered Sep 23 '22 08:09

DevSolar


6.7/3 says that

A program that jumps from a point where a local variable with automatic storage duration is not in scope to a point where it is in scope is illformed unless the variable has POD type (3.9) and is declared without an initializer (8.5).

So that should be ok.

Then in 6.6/2:

On exit from a scope (however accomplished), destructors (12.4) are called for all constructed objects with automatic storage duration (3.7.2) (named objects or temporaries) that are declared in that scope, in the reverse order of their declaration.

Now this implies to me that a is toast when you jump back to z and you cant' make any guarantees about how the no-initializer declaration of a will behave the second time it executes.

See 6.7/2:

Variables with automatic storage duration (3.7.2) are initialized each time their declarationstatement is executed. Variables with automatic storage duration declared in the block are destroyed on exit from the block (6.6).

So it looks to me like there isn't a guarantee that you'll get 10 although it seems hard to imagine a compiler where that wouldn't be the case.

like image 34
Mark B Avatar answered Sep 21 '22 08:09

Mark B