• C

"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.
lostinspace9Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

ozoCommented:
There is no statement after CMEa:    
try

      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:
     1;            
}
0
HooKooDooKuCommented:
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".
0
lostinspace9Author Commented:
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.
0
Determine the Perfect Price for Your IT Services

Do you wonder if your IT business is truly profitable or if you should raise your prices? Learn how to calculate your overhead burden with our free interactive tool and use it to determine the right price for your IT services. Download your free eBook now!

ozoCommented:
Can you post a complete example of actual code that exhibits the problem?

Could CMEa have been declared as a macro?
0
sarabandeCommented:
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
0
sarabandeCommented:
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
0
HooKooDooKuCommented:
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;
  }
0
sarabandeCommented:
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
0
HooKooDooKuCommented:
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

0
lostinspace9Author Commented:
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
            }
0
HooKooDooKuCommented:
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
0
HooKooDooKuCommented:
I know this is going to be a stupid question (because the answer above seems like a silly thing to have explain to anyone who has ever done any programming before)... but...

1. We are talking about the C (or C++) programming language?
2. Do you understand the flow control of all the following C key word?
    if - else
    for loop (with the optional 'break' and 'continue')
    while (with the optional 'break' and 'continue')
    do - while (with the optional 'break' and 'continue')
    switch - case - default (with optional 'break')
    return
    goto
0
sarabandeCommented:
I would argue that for very simple clean-up, calling a function can be more complex than using a goto
bool foo()
{
  char* pCh = new char[12];
  ...
  if( X ) return foo_cleanup( pCh );
  ...
  if( Y ) return 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;
}

Open in new window


the code using an appropriate function has one statement less.

I think that in the last 20 years, I've only encountered two (three tops) situations where the goto was the cleaner method.
if you have code that might grow or might be maintained by someone else, you never could speak of cleaner code when using goto. it always would give the code a potential risk which is higher than any other code that does not use goto. do you go angry with me if i say that code that never grows or only is maintained by yourself is fun code?

Just for fun, enclosed is the said function.  It is a part of an optimized implementation of an edge detection software:
isn't it the classical case of a state machine?

BOOL CBlobFind::FindEdge( int row, int col, eDirection Direction )
{
    ResetBlobData(row, col);
    eDirection nextDir = Direction;
    BOOL ret = FALSE;
    struct StateDecision
    {
       int rowstep;
       int colstep;
       EDirection next;
    };
    StateDecision States[4][8] = 
    {
        { { 0, 1, East }, { 1, 0, East }, { 0, -1, South }, { 0, -1, South }, { -1, 0, West }, { -1, 0, West }, { 0, 1, North }, { 0, 1, North }, },
        { { 1, 0, South }, { 0, -1, South },  { -1, 0, West }, { -1, 0, West },{ 0, 1, North }, { 0, 1, North }, { 1, 0, East }, { 1, 0, East  }, },
        { { 0, -1, West }, { -1, 0, West }, { 0, 1, North }, { 0, 1, North }, { 1, 0, East }, { 1, 0, East  }, { 0, -1, South }, { 0, -1, South }, },
        { { -1, 0, North }, { 0, 1, North }, { 1, 0, East }, { 1, 0, East  }, { 0, -1, South }, { 0, -1, South }, { -1, 0, West }, { -1, 0, West }, },
    };

    bool goon = true;
    while (goon && !(ret = IsFinished(row, col)))
    {
        goon = false;
        for (int i = 0; i < 8; ++i)
        {
            States & s = States[nextDir][i];
            if (IsBlob( row += s.rowstep, col += s.colstep)) 
            {
                nextDir = s.next;
                goon    = true;
                break;
            }
        }
    }    
    return ret;
}

Open in new window


note, instead of goon I could have used a goto :).

Sara
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
lostinspace9Author Commented:
Thanks for all of the suggestions, I have learned quite a bit.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C

From novice to tech pro — start learning today.