In C why do you need a statement after a goto label? - c

I am writing some C code and in my code I have two nested loops. On a particular condition I want to break out of the inner loop and continue the outer loop. I tried to achieve this using a label at the end on the outer loop's code and, on the condition, goto that label. However gcc gives an error that I cannot have a label at the end of a compound statement. Why not?
Note 1: This is not a switch statement and that question has been answered elsewhere.
Note 2: This is not a question about style and whether I should or should not be using goto statements or conditional variables instead.
EDIT: People have asked for an example and I can give a slightly facile example of checking if an array is a subarray of another array
int superArray[SUPER_SIZE] = {...}, subArray[SUB_SIZE] = {...};
int superIndex, subIndex;
for (superIndex=0; superIndex<SUPER_SIZE-SUB_SIZE; superIndex+=1)
{
for (subIndex=0; subIndex<SUB_SIZE; subIndex+=1)
if (superArray[superIndex+subIndex] != subArray[subIndex])
goto break_then_continue;
// code that executes if subArray is a sub array
break_then_continue:
}

In the standard it's explicitly said that labels belong to a statement, therefore a simple semicolon (;) after your label can circumvent the problem you are running in to, since that counts as a statement.
There is even an example of the use of an "empty"1 statement in 6.8.3/6.
EXAMPLE 3 A null statement may also be used to carry a label just
before the closing } of a compound statement
while (loop1) {
/* ... */
while (loop2) {
/* ... */
if (want_out)
goto end_loop1;
/* ... */
}
/* ... */
end_loop1: ;
}
1 In the standard this is referred to as a null statement.
6.8.1 Labeled statements
Syntax
1 labeled-statement:
identifier : statement
case constant-expression : statement
default : statement
Notice that statement isn't optional in the above quotation.
open-std.org: n1124.pdf

You simply need to write:
label: ;
The semi-colon is an empty statement. You need it because the language is defined like that; you need to go to a statement, even if it is an empty one.
for (int i = 0; i < N; i++)
{
for (int j = 0; i < M; j++)
{
...
if (some_condition)
goto continue_loop1;
...
}
continue_loop1: ;
}
You can argue about the indentation on the label.

The label should point to a statement.
C mandates this:
(C99, 6.8.1 Labeled statements p4) "
Any statement may be preceded by a prefix that declares an identifier as a label name."
In your case you can use a null statement:
void foo(void)
{
goto bla;
bla:
;
}
Null statements perform no operation.
Or you can also use a compound statement (a block) if you have declarations:
void foo(void)
{
goto bla;
bla:
{
int x = 42;
printf("%d\n", x);
}
}

Related

Case statement with braces

Why does a case statement allow declarations within braces but not without them?
For example, the following is not OK
switch (op->name) {
case 0:
int a = 2;
case 1:
int b = 3;
}
But the following is OK:
switch (op->name) {
case 0:
{int a = 2;}
case 1:
{int b = 3;}
}
What does the braces resolve that, without them, a declaration would be ambiguous to the compiler? To me (a beginner in C) it seems like each case statement should have an implied braces until the next case/default/end-of-switch, but that is obviously wrong!
Why does a case statement allow declarations within braces but not without them?
My compiler emits this error message:
error: a label can only be part of a statement and a declaration is not a statement
That's pretty clear I think. Labels, including case labels, are not considered independent statements or declarations, but rather components of statements. When control branches to a label, whether via a switch or a goto, it is the statement of which the label is a part to which the program jumps. Not to the label itself, which typically has no runtime representation.
Declarations such as int a; are not statements, and labels cannot be part of declarations. On the other hand, blocks such as { int a; } are statements, and as statements, they can have labels.
There's no fundamental underlying constraint here. It would have been possible for C syntax to have been defined differently, so that both of your examples were valid. It just wasn't.
The reason this is invalid:
switch (op->name) {
case 0:
int a = 2;
case 1:
int b = 3;
}
Is because you have a label (in this case a case label) in front of a declaration. A label may only appear before a statement.
Using braces works because they are used to denote a compound statement, which is a particular type of statement, and a statement can immediately precede a label.
Formally, a label is part of a labeled statement. This is spelled out in section 6.8.1 of the C standard:
labeled-statement:
identifier : statement
case constant-expression : statement
default : statement
Try this, and you'll get no error:
switch (op->name) {
case 0:; /* <--- that ; is essential, see below */
int a = 2;
case 1:; /* <--- the same here. */
int b = 3;
}
The problem is that the case statement is a special case of statement, but a declaration is not a valid substitute of a statement, so a declaration is not allowed immediately after a case label. But you can always end the case_statement with a semicolon (issuing a null statement), and put your declaration right after it.

What is a null statement in C?

I want to know exactly, what is a null statement in C programming language? And explain a typical use of it.
I found the following segment of code.
for (j=6; j>0; j++)
;
And
for (j=6; j>0; j++)
From the msdn page:
The "null statement" is an expression statement with the expression missing. It is useful when the syntax of the language calls for a statement but no expression evaluation. It consists of a semicolon.
Null statements are commonly used as placeholders in iteration statements or as statements on which to place labels at the end of compound statements or functions.
know more: https://msdn.microsoft.com/en-us/library/1zea45ac.aspx
And explain a typical use of it.
When you want to find the index of first occurrence of a certain character in a string
int a[50] = "lord of the rings";
int i;
for(i = 0; a[i] != 't'; i++)
;//null statement
//as no operation is required
A null statement is a statement that doesn't do anything, but exists for syntactical reasons.
while ((*s++ = *t++))
; /* null statement */
In this case the null statement provides the body of the while loop.
or (disclaimer: bad code)
if (condition1)
if (condition2)
dosomething();
else
; /* null statement */
else
dosomethingelse();
In this case the inner else and null statement keeps the outer else from binding to the inner if.
From C11, §6.8.4.1, 6.8.3 Expression and null statements:
A null statement (consisting of just a semicolon) performs no
operations.
The standard also provides a couple of common uses of it:
EXAMPLE 2 In the program fragment
char *s;
/* ... */
while (*s++ != '\0')
;
a null statement is used to supply an empty loop body to the iteration
statement.
6 EXAMPLE 3 A null statement may also be used to carry a label just
before the closing } of a compound statement.
while (loop1) {
/* ... */
while (loop2) {
/* ... */
if (want_out)
goto end_loop1;
/* ... */
}
/* ... */
end_loop1: ;
}
A null statement doesn't DO anything, hence the solo ';'
so....this code block will do nothing 10x in C/C++
for(int i = 0; i < 10; i++){//execute the following 10 times
;//nothing aka "null statement"
}//end for
Sometimes the null statement serves. In the "old days" the math hardware might not return an integer value when you needed one, such as returning 0.999... as sin(pi / 2), (that is sin(90 degrees)).
int i, j, k;
i = something;
for(j = 1; (2 * j) <= i; j *= 2);
Computes in j the largest integer power of 2 less than i. Not very efficient for large i but useful if you could not trust Log functions to return an exact integer value.
My C++ compiler does not accept the null statement as a function body, but does accept the "empty statement" which I think is just an empty statement block "{}".
Whether C or java, null has a special significance.
Whenever there is a need of re-intializing of values to variavle, null serves the purpose.
If there is a String i, and we want it to add a char value through a loop, then first we have to intialize i with null.

Validity of forcing at least one iteration of for loop with goto statement

Disclaimer: I know it is obscure, and I would not program like that. I am aware of the preferred do-while statement, rather than that, the question is more about validity of a specific language construct.
Is goto always supposed to omit conditional expression of the for loop? From what I observed it skips both the first (i.e. initializing) and second expressions. Will this always happen this way or is this behavior purely compiler dependent?
#include <stdio.h>
int main(void)
{
int m = 5;
goto BODY;
for (m = 0; m < 5; m++)
BODY: puts("Message"); // prints "Message" once
printf("m = %d\n", m); // prints m = 6
return 0;
}
Yes, you're jumping over both m = 0 and m < 5, and this is as it should be.
for (A; B; C)
D;
is equivalent to
{
A;
loop:
if (B)
{
D;
C;
goto loop;
}
}
There is no way to transfer control to a point between A and B.
The semantics of your loop are exactly like this "pure goto" version:
int m = 5;
goto BODY;
m = 0;
loop:
if (m < 5)
{
BODY: puts("Message"); // prints "Message" once
m++;
goto loop;
}
printf("m = %d\n", m); // prints m = 6
Does goto is always supposed to omit conditional expression of the for
loop?
Yes. A goto jump is always an unconditional jump and the execution will carry from the label from there.
From C11 draft, § 6.8.6.1 The goto statement:
A goto statement causes an unconditional jump to the statement
prefixed by the named label in the enclosing function.
With the only exception being:
The identifier in a goto statement shall name a label located
somewhere in the enclosing function. 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.
The goto statement in your code is causing an unconditional jump to a statement inside a for loop.When that statement is executed,the flow of the program is supposed to be dependent on the conditional expression in the loop.So,yes initialization inside the loop is skipped.
You should use a do/while loop, for example if you have the following for loop:
for(A ; B ; C)
{
D;
}
You should use the following do/while loop:
A;
do
{
D;
C;
}while(B);
which will force a first iteration.
EDIT
See the comment by chux: If D; contains continue, this way will not work, you will need another way
EDIT II
As the question was edited, this answer is no longer the direct answer to the question, but I won't remove it as it might helps someone...
This is perfectly legal in c. There's nothing wrong in jumping into a for loop so long as you don't skip over any declarations or initialisations of automatic variables.
In you case, m is incremented once and the loop terminates due to the stopping condition being met.
A goto statement in C programming provides an unconditional jump from the 'goto' to a labeled statement in the same function.
Note the unconditional term here.
so yes it is supposed to omit conditional expression of for loop.

Adding a `;` at the end of while loop

#include<stdio.h>
int main()
{
int i=5;
while(i--)
{
printf("%d\n",i);
};
printf("Out of loop\n");
return 0;
}
This code works fine! Does ; at the end of a loop not mean anything?
So even if we add it, we don't have any problems? Just curious! I think adding ; at the end of a loop doesn't make any sense.
It "works", but it's an empty statement so it changes the structure of your program.
Consider this:
if (foo())
while (bar())
{
foo_some_more()
}
else
{
do_something_about_it();
}
The above works since the while is a single statement, and thus the else is still able to "find" the if properly. If you add a semi-colon after the while-loop's closing brace, you break that structure and it will no longer compile.
So, although empty statements can look harmless, they are not so they really should be avoided. Plus: they add pointless confusion to the code, of course.
The ; here is considered as an empty statement or null statement.
Sample
int i = 0;;
For more information, you can check this question.
Word of Caution: Don't consider this as a thumb rule. There are cases where the representation may appear same, but they are not null statement but part of a syntax. Example: do..while loop
A superfluous ; is an empty statement and is redundant in this particular instance.
One instance where you're required to use an empty statement is in a switch to a final branch that does nothing:
switch (expression)
{
case 1:
/*Some statements here or empty*/
case 2:
; /*A statement is required between here and the closing brace
An empty statement will suffice.*/
}
You ought to avoid using superfluous empty statements; they can emit bugs (particularly if you enclose your code in if statements during a refactoring effort), and older compilers will complain. Using excess semicolons in macros is particularly pernicious.
These are Perfectly Valid, They are called Empty statements,They do nothing.
int main()
{
;
;
;
;
{
}
return 0;
}
As stated by various users above, the relevant semi-colon is an empty statement and has no effect.
This however is a slightly different story:
#include <stdio.h>
int main()
{
int i=5;
while(i--); //<--- Put the semi-colon here and see what you get.
{
printf("%d\n",i);
}
printf("Out of loop\n");
return 0;
}
#include<stdio.h>
int main()
{
int i=5;
while(i--)
{
printf("%d\n",i);
}/*blank statement*/;
printf("Out of loop\n");
return 0;
}
it's just a blank statement.
above The braces itself tells end of the block so then it would treat the ; as blank stament

Any difference between these two while loops?

while ((R_SPI2SR & B_SPIF) != B_SPIF)
{
SERIAL_SERVICE_WDOG;
};
while ((R_SPI2SR & B_SPIF) != B_SPIF)
{
SERIAL_SERVICE_WDOG;
}
I like to know what is the purpose in putting semicolon..
The semicolon after the first loop is not a part of that loop at all. It is interpreted as a completely independent empty statement that sits between the loops. I.e. your actual loops are seen as absolutely identical by C language.
The statement executed by the while loop is the compound statement inside the curly braces. The semicolon is just a gratuitous empty statement. You could have written this loop as:
while ((R_SPI2SR & B_SPIF) != B_SPIF)
SERIAL_SERVICE_WDOG;
since the compound statement just has a single statement inside it, or as
while ((R_SPI2SR & B_SPIF) != B_SPIF)
{
SERIAL_SERVICE_WDOG;;;;;;;;;;;;;;;
};;;;;;;;;;;;;;
which of course is awful style.
An empty statement is used when you have a loop that needs no body.
/* Throw away remaining characters up to the end of line. */
while ( ( c = getchar() ) != '\n')
;
You want to watch out for the classic error of ending a loop prematurely:
int i = 1;
int j = 1;
while ( i < 10 ); /* The semicolon here ends the loop... */
j *= i++; /* ... so this statement is only executed once. */
Unnecessary semicolons are just clutter, so you should never use them.
the only different in the code is the additional semicolon.
but the compiled assembly are the same.

Resources