Case statement with braces - c

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.

Related

Syntax of switch statement in C?

I am trying to understand the switch statement in C (I am using gcc from Ubuntu v16.04). I am able to understand its semantics, but have the following 2 questions about its syntax:
I have noticed after reading a few examples of usage of switch statement that the symbol after case is sometimes enclosed in '' and sometimes it isn't.
eg: case 1 or case 'a'.
I checked the Linux manpage for the switch statement (https://linux.die.net/man/1/switch) and there they have not used ' ' for a string. So I don't know what to do.
Sometimes the block of code within a single case is enclosed in a { } and sometimes it is not. I had read before that multi-line statements need to be enclosed in a { }, but not necessarily for single-line statements as in a for loop,while loop with single line statements etc. But sometimes a case statement has 1 line of code (for eg a *= 5;) followed by break statement (so total 2 statements) and yet both lines are not enclosed in { }. The Linux manpages haven't mentioned this. Can someone clarify this?
(1) 'a' is ascii value 97. Ascii is a standard way of encoding characters and it's used in many other languages as well. Essentially, each character is represented as a numerical value. So when you have:
...
case 'a':
...
you are actually executing the code below the case if the switch variable is equal to 97. In your example:
case '1':
checks if the switch variable is equal to char '1', which is ascii value 49.
(2) Enclosing a case statement with braces changes the scope of the variables between the braces. Consider the following example:
switch (sw) {
case 1:
int b = 2;
sw += b;
break;
case 2:
int b = 3;
sw += b;
break;
default:
break;
}
This is because in case 1 and case 2, you are instantiating an integer called "b". Since both case statements are in the same variable scope (the switch statement's scope), the compiler gives you an error since you are instantiating a variable with the same name and type twice. Now consider the code below:
switch (sw) {
case 1: {
int b = 2;
sw += b;
break;
} case 2: {
int b = 3;
sw += b;
break;
} default: {
break;
}
}
This code compiles. By enclosing each case's code in braces, you are giving each case its own variable scope, where it could redefine the same variable once in each scope.
To answer your questions:
q1: 1 and '1' are not the same. The latter is surrounded by single-quotes, which in C always represent a character. Depending on the C implementation, this character would be stored in the ASCII format, with the numerical representation 49. Seeing as a character in ASCII format is guaranteed the ability to be represented numerically, but a number isn't, the comparison '1' == 1 is legal, because the character will be implicity converted to an integer.
q2: Enclosing a case in curly braces is optional. You can declare a scope at any time using curly braces. More information: https://www.geeksforgeeks.org/scope-rules-in-c/, C Switch-case curly braces after every case
(1) You're asking about the switch statement in C (specifically, gcc), but the link you included is for the switch statement in a Linux shell. These are two different languages!
In C, the single quote '' is used for characters. A character is a single letter/number/symbol/etc, as opposed to a string which is one or more characters. So case 1: will match the number 1, and case '1': will match the character '1'. A number has a type like int or long. A character has the type char. So whether you use '' or not depends on if you're trying to match a character or a number.
(2) The { } are not necessary. You might choose to use them to visually group the block of code, but you don't have to. You also can use { } to limit the scope of a variable. Variable scope is a big topic, see this for more info: https://www.w3schools.in/c-tutorial/variable-scope/
There's no man page for the switch used in C. What you're looking at is the man page for the switch command (as per the (1) in the name), something totally different.
A case needs to use single quotes for a character constant and no single quotes for a non-character constant.
For example, case '1': checks for the character '1' (typically with an integer value of 49), and case 1: checks for the integer value 1.
The curly braces are mostly a preference of style. Some people think the curly braces makes their code look nicer and/or clearer, and some don't. There's no difference except for scope.
This allows you to define a variable within an individual case label so you don't make it available to the whole function or switch statement.

Why can't I "goto default;" or "goto case x;" within a switch selection structure?

Section 6.8.1 of C11 or C99, or section 3.6.1 of C89 all seem to indicate that default and case x (where x is some constant-expression) are examples of labeled statements, along-side identifier:-style labels that are suitable for use with goto.
I'm aware that I could simply place an identifier:-style label directly following the default: or case x: labels. That's not what this question is about. I'm more curious as to whether there is any actual rationale behind prohibiting this kind of behaviour.
If it were possible to declare default: labels outside of a switch selection structure, then I would understand, as there would be some conflict between where the goto inside of the switch selection structure is intended to aim. However, section 6.4.1 of C11 or C99 or 3.1.1 of C89 prohibits the use of default as anything other than a keyword, and 6.8.1 restricts its use further to switch structures only (or generic structures in C11, which are irrelevant here).
I would also understand if multiple (possibly nested) switch structures, each with default: (or case x:) labels introduced ambiguity, however the scope of those labels seems to be restricted to within their inner-most surrounding switch structures, and referring to any identifier outside of its scope is clearly an error requiring a diagnostic at compile-time.
Has this been discussed in any standard documents (e.g. the rationale)? Is there any kind of explanation for this behaviour other than "it is because it is" or "because the spec says so"? If so, what is that explanation?
(I don't see how goto to a case would work syntactically.)
As you say, case and default labels only have the scope of the corresponding switch statement and can only be jumped to from outside. On the other hand
labels in C have function scope and can be jumped to from anywhere in the function.
So we are talking of labels with a quite different properties, they are probably treated quite different, internally. It seems relatively complicated to reconcile these properties and would make implementing this more complicated. All of a sudden you would have to have to decide when implementing goto which case or default is the correct one, whereas now you just have to put the address of the file scope identifier, there.
All of this said, this is just a guess about the original intentions for this distinction. But I am sure that argumentation along these lines would quickly kill any attempt to introduce such a feature now.
counter example
fun() {
switch (b) {
case x:
doSomething();
break;
}
switch(b2) {
case x:
doMore();
break;
}
goto x; // which one?
}
ISO/IEC 9899:2011 Information technology -- Programming languages -- C
6.8.1 Labeled statements
Syntax
labeled-statement:
identifier : statement
case constant-expression : statement
default : statement
A case or default label shall appear only in a switch statement. Further constraints on such labels are discussed under the switch
statement.
Label names shall be unique within a function.
Any statement may be preceded by a prefix that declares an identifier as a label name. Labels in themselves do not alter the
flow of control, which continues unimpeded across them.
6.8.6 Jump statements
Syntax
jump-statement:
goto identifier ;
6.8.6.1 The goto statement
The identifier in a goto statement shall name a label located somewhere in the enclosing function.
A goto statement causes an unconditional jump to the statement prefixed by the named label in the enclosing function.
6.2.1 Scopes of identifiers
A label name is the only kind of identifier that has function scope. It can be used (in a goto statement) anywhere in the function in which it appears, and is declared implicitly by its syntactic appearance (followed by a : and a statement).
case, default labels are not identifiers, named labels.
"Because the spec says so." Do not overthink it.
I'm aware that I could simply place an identifier:-style label directly following the default: or case x: labels. That's not what this question is about. I'm more curious as to whether there is any actual rationale behind prohibiting this kind of behaviour.
At cost of sounding tautologic, the rationale is that each case is intended to be uniquely jumped into from one single goto (the one created by the switch statement). Which is also why we need to group together more case labels if we want a block of code to be executed in case of more than one condition.
The following code might give you a visual answer. If goto [case label] were allowed, what would you write in order to go to the first case, goto case 'q' or goto case 'e'? Which one is the boss of that block of code?
#include <stdio.h>
int yes_or_no (char input, char additional_yes) {
int retval;
switch (input) {
case 'q':
case 'e':
printf("Bye bye! :-)\n");
retval = 0;
break;
case 'n':
printf("I am very sad that you said no :-(\n");
retval = 0;
break;
case 'y':
other_yes:
printf("Thank you for saying yes! :-)\n");
retval = 0;
break;
case '\n':
case '\r':
case ' ':
case '\t':
case '\v':
case '\f':
printf("Mmmmm... maybe you need time to think...\n");
retval = 1;
break;
default:
if (input == additional_yes) {
goto other_yes;
}
printf("\"%c\" is not an answer!\n", input);
retval = 1;
}
return retval;
}
int main (int argc, char *argv[]) {
printf("Please, answer (yes/ja or no/nein) -- e or q to quit\n");
while (yes_or_no(getchar(), 'j'));
return 0;
}
Consider also that, while optimizing, the compiler might decide not to use jump tables at all if it thinks that a simple repeated if would be faster than a switch (this might happen especially when the case labels are not many). In this case, if goto [case label] were allowed, you would force the compiler to create a label where normally there wouldn't be one.
This is one of the things I like most of C: if you want something you have to say it.

What are the other forms of switch statement in C?

I'm reading KN King's A Modern Approach to C Programming, 2nd edition.
It says, there are also other forms of switch statement besides general switch statement (with case keyword).
The general form of switch statement is
switch (exp)
{
case constant-exp:
statement;
break;
case constant-exp:
statement;
break;
...
...
default:
statement;
break;
}
It also says (in Q&A) switch statement can have form with no case keyword for example.
I tried running an example with no case keyword, but it doesn't run (under std=-c99).
So, I wanted to know what are the other forms of switch statement that are valid in Standard C99.
EDIT: Cited fro BOOK
In it's most common form, the switch statement has the form
switch ( expression ) {
case constant-expression : statements
...
case constant-expression : statements
default : statements
}
Q&A
**Q: The template given for the switch statement described it as the "most common form." Are there other forms?
A**: The switch statement is a bit more general than described in this chapter, although the description given here is general enough for virtually all programs.
For example, a switch statement can contain labels that aren't preceded by the word case, which leads to amusing (?) trap. Suppose that we accidentally missell the word default:
switch(...) {
...
defualt: ...
}
The compiler may not detect the error, since it assumes that defualt is an ordinary label.
The syntax of a switch statement is:
switch ( expression ) statement
where the statement portion is typically a block (compound statement) containing labeled statements of the form:
case constant-expression : statement
or
default : statement
A switch statement isn't required to contain case or default labels, but there's no point in using a switch if you're not going to have one or more such labels. For example, this:
switch (42);
is a perfectly legal switch statement (the controlled statement is the null statement ;), but it's also perfectly useless.
I suspect you've misunderstood what the book says.
Your quote from the book says:
For example, a switch statement can contain labels that aren't
preceded by the word case, which leads to amusing (?) trap. Suppose
that we accidentally mispsell the word default:
switch(...) { ... defualt: ... }
The contents of a switch statement should be a block containing a sequence of case and default labels, each one ending either with a break or with a comment indicating that the control flow falls through to the next case. The point is that the language doesn't require this; the way it specifies the syntax gives you a lot of freedom (perhaps too much!). The only restriction is that case and default labels cannot appear outside a switch statement.
For example, suppose you accidentally write:
enum blah { foo, bar, baz };
switch (expr) {
case foo:
/* ... */
break;
bar: /* forgot the `case` keyword */
/* ... */
break;
defualt: /* misspelled "default" */
/* ... */
break;
}
Neither bar: nor defualt: was what was intended -- but they're both perfectly legal. They're ordinary labels, the kind that can be the target of a goto statement. Since there is no goto targeting either label, the corresponding chunks of code will never be executed. If expr is equal to foo, it will jump to the case foo:; for any other value, it will jump to the end of the switch statement.
And because they're perfectly legal, a compiler won't necessarily warn you about the error.
This is a common phenomenon in C. The grammar is so "dense" that a seemingly minor typo can easily give you something that's syntactically valid, but whose behavior is entirely different from what you intended.
Crank up the warning levels on your compiler, and pay attention to all the warnings you see. And be careful; the responsibility for writing your code correctly is ultimately yours. The compiler can help, but it can't catch all errors.
Regarding your observation: there are also other forms of switch statement besides general switch statement (with case keyword) Generally, the switch statement is very well documented, but there are a few interesting variations in the way the case statements are used...
Although nothing Earth shaking here, It may be useful to note: Sun (a flavor of unix) and GNU C compiler have an extension that provides case ranges for use with the switch() statement. So, for example, rather than using the classic syntax:
:
case 'A':
case 'B':
:
case 'Z':
//do something here.
break;
and so on...
A case range syntax can be used to delineate the conditions:
switch(input) {
case 'A' ... 'Z':
printf("Upper case letter detected");
break;
case 'a' ... 'z':
printf("Lower case letter has been detected");
break;
};
Important Note:, case ranges are not part of the C standard (C99 or C11) rather only an extension of the environments I have mentioned, and in no way should be considered portable. Case ranges are gaining in popularity (or at least in interest) and may be included as part of the C standard at some point, but not yet (AFAIK).
The go-to source for C-99 is the C-99 standard, though of course C-99 has been replaced by C11. The switch statement is on page 134 of the C-99 standard. They give an example of what is probably the most non-general switch statement you can have:
EXAMPLE In the artificial program fragment
switch (expr)
{
int i = 4;
f(i);
case 0:
i=17;
/* falls through into default code */
default:
printf("%d\n", i);
}
the object whose identifier is i exists with automatic storage duration (within the block) but is never
initialized, and thus if the controlling expression has a nonzero value, the call to the printf function will
access an indeterminate value. Similarly, the call to the function f cannot be reached.
Note the ways that this is not "standard" (and is generally bad code).
You have code that is not under any case or default label. In fact, nothing but identifier declarations seems to be acknowledged, so that i is a valid variable within the scope of the switch statement, but setting it or calling functions without a case or default label causes errors.
What I think the author wanted you to notice was that it's valid to not have a break under each label. In this example, case 0 falls through to the default label, but if there were other case labels beneath case 0, it would go through each one until you did hit a break statement.
For that matter, though not in this example, you can put the default label first. Again, if you don't put a break after it, you'll execute code under any following labels.
As I mentioned in my comment, you could just have a default label if you want, but that effectively renders the switch statement meaningless:
switch (exp)
{
default:
statement;
}
that's effectively equivalent to { statement; }.
Incidentally, you can do some clever (but confusing) tricks with avoiding break statements, e.g. this is a valid (though less efficient than c - '0') way to convert a digit character c to an integer:
int i = 0;
switch (c) {
case '9': ++i;
case '8': ++i;
case '7': ++i;
case '6': ++i;
case '5': ++i;
case '4': ++i;
case '3': ++i;
case '2': ++i;
case '1': ++i;
case '0':
default:
}
Wiki describes how the switch statement defined as below considering different coding languages,
In most languages, a switch statement is defined across many individual lines using one or two keywords. A typical syntax is:
1. The first line contains the basic keyword, usually switch, case or select,
followed by an expression which is often referred to as the control expression
or control variable of the switch statement.
2. Subsequent lines define the actual cases (the values) with corresponding
sequences of statements that should be executed when a match occurs.
Each alternative begins with the particular value, or list of values, that the control variable may match and which will cause the control to go to the corresponding sequence of statements. The value (or list/range of values) is usually separated from the corresponding statement sequence by a colon or an implication arrow. In many languages, every case must also be preceded by a keyword such as case or when. An optional default case is typically also allowed, specified by a default or else keyword; this is executed when none of the other cases matches the control expression.

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

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);
}
}

Are local variables in a compound switch statement initialized when the `default:` label is put outside the braces?

Normally when using a switch statement, you cannot define and initialize variables local to the compound statement, like
switch (a)
{
int b = 5; /* Initialization is skipped, no matter what a is */
case 1:
/* Do something */
break;
default:
/* Do something */
break;
}
However, since the switch statement is a statement like for or while, there is no rule against not using a compound statement, look here for examples. But this would mean, that a label may be used between the closing parenthesis after the switch keyword and the opening brace.
So in my opinion, it would be possible and allowed to use a switch statement like this:
switch (a)
default:
{
int b = 5; /* Is the initialization skipped when a != 1? */
/* Do something for the default case using 'b' */
break;
case 1: // if a == 1, then the initialization of b is skipped.
/* Do something */
break;
}
My question: Is the initialization necessarily performed in this case (a != 1)? From what I know of the standards, yes, it should be, but I cannot find it directly in any of the documents I have available. Can anyone provide a conclusive answer?
And before I get comments to that effect, yes, I know this is not a way to program in the real world. But, as always, I'm interested in the boundaries of the language specification. I'd never tolerate such a style in my programming team!
Most people think of a switch as a mutiple if, but it is technically a calculated goto. And the case <cte>: and default: are actually labels. So the rules of goto apply in these cases.
Your both your examples are syntactically legal, but in the second one, when a==1 the b initialization will be skipped and its value will be undefined. No problem as long as you don't use it.
REFERENCE:
According to C99 standard, 6.2.4.5, regarding automatic variables:
If an initialization is specified for the object, it is performed each time the declaration is reached in the execution of the block;
So the variable is initialized each time the execution flow reaches the initialization, just as it were an assignment. And if you jump over the initialization the first time, then the variable is left uninitialized.

Resources