Link to home
Start Free TrialLog in
Avatar of lostinspace9
lostinspace9

asked on

"goto" Function Error

In the snippet below:

      if (Tag >= 64)
            {
                  a = b;                              //dummy calculation
                  goto NextCheck;
            }      
            else
            {            
                  a = b;                               //dummy calculation      
                  goto CMEa;         
            }
             
NextCheck:            
      
      if (Tag >= 60)
            {
                  a = b;                              //dummy calculation
            }
      else
            {
                  a = b;                              //dummy calculation
            }      
                                
CMEa:              
}

I get this error message:

DataSel.c:9: error: expected identifier or '*' before string constant
DataSel.c:23: error: expected ';' before ':' token

The compiler does not like the "goto CMEa;" line or the "CMEa:" line.  

If I comment out those two lines the code will work.
SOLUTION
Avatar of ozo
ozo
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of HooKooDooKu
HooKooDooKu

ozo has the right diagnosis, but IMHO, just sticking a command of '1;' is confusing (and was actually surprised that it compiled.

However, you can still insert what in Assembly Language was known as a NOP (no operation) by simply using the semi-colon by-it-self.

CMEa:
     ;            
}

But actually, I like to insert a NOP like this.

CMEa:
    /*NOP*/;
}

That way it is painfully obvious you don't want to do anything here.  

I'll also insert the same line into empty functions  (such as constructors or a destructor) just to again make it plan that it was my intention for there to be no executable source code here.

Class1::Class1()
{
    /*NOP*/;
}

It's sort of like seeing a document with a page labelled "This page intentionally left blank".
Avatar of lostinspace9

ASKER

Thanks guys,

However, you are only seeing a snippet of the actual code, quite a bit comes after CMEa.  The code contains a lot of logic testing and I am breaking down each module to test things.  My problem is with the second goto statement.  I cannot find an explanation "before string constant" and was hoping that you could help.  I think if we can fix it the second one will be solved as well.

Even though I do not need a NOP in this code I tried them (in the snippet above) and they worked.  The NOP I was going to use when needed was:  int NOP; ...code... NOP=0; .   I like both of yours better and can think of a time and place for each.

Anyway, what about that pesky "before string constant" problem?

Thanks again.
Can you post a complete example of actual code that exhibits the problem?

Could CMEa have been declared as a macro?
why are you using goto in your code at all?

i don't think that a well-structured code needs a goto. a goto is error-prone as your code may omit important initializations or assignments. you always can implement a block like that below NextCheck with a function. also an error block more easily can be implemented by a function.

Sara
Even though I do not need a NOP in this code I tried them (in the snippet above) and they worked.  The NOP I was going to use when needed was:  int NOP; ...code... NOP=0; .  

can you tell what you mean by that? did you really add an (uninitialized) integer and make a dummy statement after the label?

what about that pesky "before string constant" problem?
if a compiler finds a issue that it can't solve, the error message not necessarily shows the real cause but only the last choice the compiler tested before it declared the code as not compilable.

i added your snippet to a c source and compiled. i got the following error:

error C2143: syntax error : missing ';' before '}'

Open in new window


what is much better than your message. if i add

#define CMEa "abc"

Open in new window


above the code, i get the following error:
error C2059: syntax error : 'string'

Open in new window

which is more alike to the one you got. you may change the label CMEa to some other name for example EndCheck and look if the error message still is the same. if not, the CMEa could be defined in some header included by your source or included by another header.

Sara
Based on the simple code snippet you've posted, I don't see any other error.

It sounds like sarabande is basically saying "you must have CMEa defined as something somewhere else".  So try something to better make sure your goto labels are unique.

For example, if your function is called 'foo()', then try goto labels like 'foo_1' and 'foo_2':

void foo()
{
    ...
    if (Tag >= 64)
    {
        goto foo_1;
    }
    else
    {
        goto foo_2;
    }

    ...

foo_1:            
    if (Tag >= 60)
    {
        ...
    }
    else
    {
        ...
    }

foo_2:
    /*NOP*/;
}
 

I would also support sarabande's question about why you are using 'goto' at all.  There is almost always another way to cleanly accomplish the same thing using do, while, for, break, and return commands.

For example, your goto statement to jump to CMEa that does nothing but end the function can be replaced with a simple return command.

I can say that I've been programming professionally for about 20 years, and there's only been three situations where I've ever needed to use Goto:

1. A function with several locations where the function needs to exit early but the same 'cleanup code' needed to execute before leaving the function.  In that case, the cleanup code was was labeled with something like 'foo_cleanup:' and 'return' was replaced by 'goto foo_cleanup'.  

2. You have several nested while/for/do loops and you need to jump from an inner loop to the outer - most loop, and the structure is such that a few break/continue commands will not get you where you need to go.  In that case, a goto is the easy way to escape.

3. A crazy algorithm that looked something like this:

X1:
  switch( foo1() )
  {
    case 1: goto X1;
    case 2: goto X2;
    case 3: goto X3;
    default: return;
  }
X2:
  switch( foo2() )
  {
    case 1: goto X1;
    case 2: goto X2;
    case 3: goto X3;
    default: return;
  }
X3:
  switch( foo3() )
  {
    case 1: goto X1;
    case 2: goto X2;
    case 3: goto X3;
    default: return;
  }
It sounds like sarabande is basically saying "you must have CMEa defined as something somewhere else".

it was ozo who first mentioned a macro.

and there's only been three situations where I've ever needed to use goto:
to (1):
you much better can solve such case by an error or cleanup function:
int cleanup_on_error(int sev, const std::string& errtext, int errcode, Context * pCtx)
{
     log_error(sev, errtext, errcode);
     cleanup(pCtx);
     return errcode;
}
...
if (whatever)
{
     return cleanup_on_error(FATAL, "whatever", 123, &localContext);
}
else
{
     ....
     {
          ....
          {
                if (something) 
                {
                    return cleanup_on_error(WARNING, "something", 999, NULL);
                    ...

Open in new window


to (2)
if using a goto to escape from a inner loop you have the logical problem that all code between the goto statement and the goto label was not executed. worse, if you later add code you may be not aware that this code was not executed when the goto was performed. i had to maintain such code and my only chance to handle it without generating new issues was to make a full redesign.

to (3)
there is no restriction of using goto in crazy code :-)

Sara
you much better can solve such case by an error or cleanup function
I would argue that for very simple clean-up, calling a function can be more complex than using a goto.  Compare:

void foo()
{
  char* pCh = new char[12];
  ...
  if( X )
  {
    foo_cleanup( pCh );
    return;
  }
  ...
  if( Y )
  {
    foo_cleanup( pCh );
    return;
  }
  ...
  foo_cleanup( pCh );
}

... compared to ...
   
void foo()
{
  char* pCh = new char[12];
  ...
  if( X ) goto foo_exit;
  ...
  if( Y ) goto foo_exit;
  ...
foo_exit:
  delete pCh;
}
 

if using a goto to escape from a inner loop you have the logical problem that all code between the goto statement and the goto label was not executed...
Jumping around in loops can definitely have pitfalls, so it is something I've only done if the jump was pretty clean and the logic was more strait forward with the jump rather than a bunch of conditional 'break' and 'continue' statements.  I think that in the last 20 years, I've only encountered two (three tops) situations where the goto was the cleaner method.


there is no restriction of using goto in crazy code :-)
Just for fun, enclosed is the said function.  It is a part of an optimized implementation of an edge detection software:
BOOL CBlobFind::FindEdge( int row, int col, eDirection Direction )
{
	ResetBlobData(row, col);
	switch( Direction )
	{
		case South: goto FindEdge1;
		case West:  goto FindEdge2;
		case North: goto FindEdge3;
		case East:  goto FindEdge4;
	}
	return FALSE;
FindEdge1: //Last Moved South or SouthWest
	if( IsFinished(row, col) ) return TRUE;
	if( IsBlob(  row,++col) ) goto FindEdge4;
	if( IsBlob(++row,  col) ) goto FindEdge4;
	if( IsBlob(  row,--col) ) goto FindEdge1;
	if( IsBlob(  row,--col) ) goto FindEdge1;
	if( IsBlob(--row,  col) ) goto FindEdge2;
	if( IsBlob(--row,  col) ) goto FindEdge2;
	if( IsBlob(  row,++col) ) goto FindEdge3;
	if( IsBlob(  row,++col) ) goto FindEdge3;
	return FALSE;
FindEdge2:	//Last Moved West or NorthWest
	if( IsFinished(row, col) ) return TRUE;
	if( IsBlob(++row,  col) ) goto FindEdge1;
	if( IsBlob(  row,--col) ) goto FindEdge1;
	if( IsBlob(--row,  col) ) goto FindEdge2;
	if( IsBlob(--row,  col) ) goto FindEdge2;
	if( IsBlob(  row,++col) ) goto FindEdge3;
	if( IsBlob(  row,++col) ) goto FindEdge3;
	if( IsBlob(++row,  col) ) goto FindEdge4;
	if( IsBlob(++row,  col) ) goto FindEdge4;
	return FALSE;
FindEdge3:	//Last Moved North or NorthEast
	if( IsFinished(row, col) ) return TRUE;
	if( IsBlob(  row,--col) ) goto FindEdge2;
	if( IsBlob(--row,  col) ) goto FindEdge2;
	if( IsBlob(  row,++col) ) goto FindEdge3;
	if( IsBlob(  row,++col) ) goto FindEdge3;
	if( IsBlob(++row,  col) ) goto FindEdge4;
	if( IsBlob(++row,  col) ) goto FindEdge4;
	if( IsBlob(  row,--col) ) goto FindEdge1;
	if( IsBlob(  row,--col) ) goto FindEdge1;
	return FALSE;
FindEdge4:	//Last Moved East or SouthEast
	if( IsFinished(row, col) ) return TRUE;
	if( IsBlob(--row,  col) ) goto FindEdge3;
	if( IsBlob(  row,++col) ) goto FindEdge3;
	if( IsBlob(++row,  col) ) goto FindEdge4;
	if( IsBlob(++row,  col) ) goto FindEdge4;
	if( IsBlob(  row,--col) ) goto FindEdge1;
	if( IsBlob(  row,--col) ) goto FindEdge1;
	if( IsBlob(--row,  col) ) goto FindEdge2;
	if( IsBlob(--row,  col) ) goto FindEdge2;
	return FALSE;
}

Open in new window

I was waiting on the comments about using the goto statement and I agree.  I cannot remember the last time I used goto, probably back in my Fortran days. However, the guys who write compilers evidently think it is a good idea to include a goto type statement.

That being said, please look at the snippet below.  When I use return in the first nested if statement it picks up in the next else statement which I cannot let happen, I need to exit the complete nested if.  Is there a cleaner way to do what I want?

Thanks for all the input.


if (Tag >= 64)
            {
                  some code...
                  
                  if (Tag >= 64)
                        {
                              some code...
                              return;
                         }
                  else
                        {
                              some code...
                        }
            }            
      else
            {            
                  cannot come here from return statement
            }
I'm sorry, but the combination of your description and your sample code do not make sense.  

For starters, a 'return' exits a function.  So once the 'return' in your sample is executed, nothing in any of the else statements will be executed... flow control will immediately return to the calling function.

Let me rewrite your sample descriptively like this:
Code Block A
if( B )
{
  Code Block B
  if( C )
  {
    Code Block C
  }
  else  //Not C
  {
    Code Block D
  }
else  //Not B
{
  Code Block E
}
Code Block F

Open in new window


Assuming there are no 'goto', 'return', 'break', or 'continue' statements in the blocks of code, there are only 3 possible execution paths thru these nested if statements:

1. if(B) == FALSE
Code Block A,
Code Block E,
Code Block F

2. if(B) == TRUE and if(C) == FALSE
Code Block A,
Code Block B,
Code Block D,
Code Block F

3. if(B) == TRUE and if(C) == TRUE
Code Block A,
Code Block B,
Code Block C,
Code Block F
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thanks for all of the suggestions, I have learned quite a bit.