Through a little typo, I accidentally found this construct:
int main(void) {
char foo = 'c';
switch(foo)
{
printf("Cant Touch This\n"); // This line is Unreachable
case 'a': printf("A\n"); break;
case 'b': printf("B\n"); break;
case 'c': printf("C\n"); break;
case 'd': printf("D\n"); break;
}
return 0;
}
It seems that the printf at the top of the switch statement is valid, but also completely unreachable.
I got a clean compile, without even a warning about unreachable code, but this seems pointless.
Should a compiler flag this as unreachable code?
Does this serve any purpose at all?
Perhaps not the most useful, but not completely worthless. You may use it to declare a local variable available within switch scope.
switch (foo)
{
int i;
case 0:
i = 0;
//....
case 1:
i = 1;
//....
}
The standard (N1579 6.8.4.2/7) has the following sample:
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.
P.S. BTW, the sample is not valid C++ code. In that case (N4140 6.7/3, emphasis mine):
A program that jumps90 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 (8.5).
90) The transfer from the condition of a switch statement to a case label is considered a jump in this respect.
So replacing int i = 4; with int i; makes it a valid C++.
Does this serve any purpose at all?
Yes. If instead of a statement, you put a declaration before the first label, this can make perfect sense:
switch (a) {
int i;
case 0:
i = f(); g(); h(i);
break;
case 1:
i = g(); f(); h(i);
break;
}
The rules for declarations and statements are shared for blocks in general, so it's the same rule that allows that that also allows statements there.
Worth mentioning as well is also that if the first statement is a loop construct, case labels may appear in the loop body:
switch (i) {
for (;;) {
f();
case 1:
g();
case 2:
if (h()) break;
}
}
Please don't write code like this if there is a more readable way of writing it, but it's perfectly valid, and the f() call is reachable.
There is a famous use of this called Duff's Device.
int n = (count+3)/4;
switch (count % 4) {
do {
case 0: *to = *from++;
case 3: *to = *from++;
case 2: *to = *from++;
case 1: *to = *from++;
} while (--n > 0);
}
Here we copy a buffer pointed to by from to a buffer pointed to by to. We copy count instances of data.
The do{}while() statement starts before the first case label, and the case labels are embedded within the do{}while().
This reduces the number of conditional branches at the end of the do{}while() loop encountered by roughly a factor of 4 (in this example; the constant can be tweaked to whatever value you want).
Now, optimizers can sometimes do this for you (especially if they are optimizing streaming/vectorized instructions), but without profile guided optimization they cannot know if you expect the loop to be large or not.
In general, variable declarations can occur there and be used in every case, but be out of scope after the switch ends. (note any initialization will be skipped)
In addition, control flow that isn't switch-specific can get you into that section of the switch block, as illustrated above, or with a goto.
Assuming you are using gcc on Linux, it would have given you a warning if you're using 4.4 or earlier version.
The -Wunreachable-code option was removed in gcc 4.4 onward.
Not only for variable declaration but advanced jumping as well. You can utilize it well if and only if you're not prone to spaghetti code.
int main()
{
int i = 1;
switch(i)
{
nocase:
printf("no case\n");
case 0: printf("0\n"); break;
case 1: printf("1\n"); goto nocase;
}
return 0;
}
Prints
1
no case
0 /* Notice how "0" prints even though i = 1 */
It should be noted that switch-case is one of the fastest control flow clauses. So it must be very flexible to the programmer, which sometimes involves cases like this.
It should be noted, that there are virtually no structural restrictions on the code within the switch statement, or on where the case *: labels are placed within this code*. This makes programming tricks like duff's device possible, one possible implementation of which looks like this:
int n = ...;
int iterations = n/8;
switch(n%8) {
while(iterations--) {
sum += *ptr++;
case 7: sum += *ptr++;
case 6: sum += *ptr++;
case 5: sum += *ptr++;
case 4: sum += *ptr++;
case 3: sum += *ptr++;
case 2: sum += *ptr++;
case 1: sum += *ptr++;
case 0: ;
}
}
You see, the code between the switch(n%8) { and the case 7: label is definitely reachable...
* As supercat thankfully pointed out in a comment: Since C99, neither a goto nor a label (be it a case *: label or not) may appear within the scope of a declaration that contains a VLA declaration. So it's not correct to say that there are no structural restrictions on the placement of the case *: labels. However, duff's device predates the C99 standard, and it does not depend on VLA's anyway. Nevertheless, I felt compelled to insert a "virtually" into my first sentence due to this.
You got your answer related to the required gcc option -Wswitch-unreachable to generate the warning, this answer is to elaborate on the usability / worthyness part.
Quoting straight out of C11, chapter §6.8.4.2, (emphasis mine)
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.
Which is very self-explanatory. You can use this to define a locally scoped variable which is available only within the switch statement scope.
It is possible to implement a "loop and a half" with it, although it might not be the best way to do it:
char password[100];
switch(0) do
{
printf("Invalid password, try again.\n");
default:
read_password(password, sizeof(password));
} while (!is_valid_password(password));
Related
I stumbled upon this code, which works as expected:
switch (ev->deviceType) {
break;
case DEVICE_TS1E0:
//some code
break;
case DEVICE_TS1E3:
//some code
break;
default:
//some logging
break;
}
Now, there's a lonesome break; at the start of the switch, which appears to have no effect.
Is there any circumstances where that break; would have an effect ?
TL;DR That break statement is ineffective and a dead-code. Control will never reach there.
C11 standard has a pretty good example of a similar case, let me quote that straight.
From Chapter §6.8.4.2/7, (emphasis mine)
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.
That statement, along any other statements that is not in a case clause in switch statement are unreachable code, aka dead code. That means they will not be run anyway. It is not recommended to use them.
I'm using Keil C on an 8051 project and I'm getting error C175 - Duplicate Case value from the following:
switch (x)
{
case 0:
break;
case 1:
break;
case 2:
switch (y)
{
case 0:
break;
case 1:
break;
}
}
Any thoughts ?
Your compiler is broken. Keil is infamous for its poor standard compliance.
C11 6.8.4.2/3
The expression of each case label shall be an integer constant
expression and no two of the case constant expressions in the same
switch statement shall have the same value after conversion. There may
be at most one default label in a switch statement. (Any enclosed
switch statement may have a default label or case constant expressions
with values that duplicate case constant expressions in the enclosing
switch statement.)
The above bold, normative text is there in any version of the C standard.
This is likely a compiler bug. With gcc your code works flawlessly: http://ideone.com/u4svzf. This is the tested code:
#include <stdio.h>
int main(void) {
int x, y;
switch (x) {
case 0:
break;
case 1:
break;
case 2:
switch (y) {
case 0:
break;
case 1:
break;
}
}
// your code goes here
return 0;
}
You cannot put "0" and "1" as case statements within another switch which has 0 and 1 for a case.
You can find the explanation here.
[EDİT]: Actually the explanation says "in the same statement" but we understand from here: in keil C we cannot enclose a switch block in a switch block. Like #niklasfi said, it runs perfectly in gcc(I tried too).
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.
This question already has answers here:
Variable definition inside switch statement
(5 answers)
Closed 5 years ago.
Code:
int main()
{
int a=1;
switch(a)
{
int b=20;
case 1:
printf("b is %d\n",b);
break;
default:
printf("b is %d\n",b);
break;
}
return 0;
}
Output:
It prints some garbage value for b
when does the declaration of b takes place here
Why b is not initialized with 20 here???
Because memory will be allocated for int b but when the application is run "b = 20" will never be evaluated.
This is because your switch-statement will jump down to either case 1:1 or default:, skipping the statement in question - thus b will be uninitialized and undefined behavior is invoked.
The following two questions (with their accepted answers) will be of even further aid in your quest searching for answers:
How can a variable be used when it's definition is bypassed? 2
Why can't variables be declared in a switch statement?
Turning your compiler warnings/errors to a higher level will hopefully provide you with this information when trying to compile your source.
Below is what gcc says about the matter;
foo.cpp:6:10: error: jump to case label [-fpermissive]
foo.cpp:5:9: error: crosses initialization of 'int b'
1 since int a will always be 1 (one) it will always jump here.
2 most relevant out of the two links, answered by me.
Switch statements only evaluate portions of the code inside them, and you can't put code at the top and expect it to get evaluated by every case component. You need to put the b initialization higher in the program above the switch statement. If you really need to do it locally, do it in a separate set of braces:
Code:
int main()
{
int a=1;
/* other stuff */
{
int b=20;
switch(a)
{
case 1:
printf("b is %d\n",b);
break;
default:
printf("b is %d\n",b);
break;
}
}
/* other stuff... */
return 0;
}
The switch directly jumps to case 1:, never executing the assignment.
Presumably because switch functions like a goto - if a == 1, it jumps straight to case 1: and bypasses initialization of b.
That is: I know switch jumps straight to the case label, but I'm very surprised the compiler doesn't complain about the missed initialization.
It's a pretty bad idea to initialize B under the switch statement and outside a case statement. To understand what's going on here, you have to know that the switch makes a jump to the correct case/default statement.
because when switch(a) statement executes control goes directly to the statement case 1: without executing statement int b=20, taht's why it gives garbage value as answer. If u want to print a then either u have to initialise in case 1: block or u have to initialise to before switch(a) statement.
Because that line is never reached. When C hits a switch(a) statement, it branches to the case that matches the condition of the variable you're switching on. The statement that initialises b isn't in any of the cases. I suppose the compiler is free to write 20 into the location, but the language doesn't require it to do so and in this case it doesn't: it's also free to leave initialisation until it actually executes an assignment.
int a = 10;
switch(a){
case 0:
printf("case 0");
break;
case 1:
printf("case 1");
break;
}
Is the above code valid?
If I am sure that int a will not have any other value than 1 and 0, can I avoid default?
What if in any case a value will be different from 1 and 0?
I know this is a silly question but I was thinking that perhaps it would be illegal or undefined behavior soI just asked to make sure.
The code is valid. If there is no default: label and none of the case labels match the "switched" value, then none of the controlled compound statement will be executed. Execution will continue from the end of the switch statement.
ISO/IEC 9899:1999, section 6.8.4.2:
[...] If no converted case constant expression matches and there is no default label, no part of the switch body is executed.
As others have pointed out it is perfectly valid code. However, from a coding style perspective I prefer adding an empty default statement with a comment to make clear that I didn't unintentionally forget about it.
int a=10;
switch(a)
{
case 0: printf("case 0");
break;
case 1: printf("case 1");
break;
default: // do nothing;
break;
}
The code generated with / without the default should be identical.
It is perfectly legal code. If a is neither 0 or 1, then the switch block will be entirely skipped.
It's valid not to have a default case.
However, even if you are sure that you will not have any value rather than 1 and 0, it's a good practice to have a default case, to catch any other value (although it is theoretically impossible, it may appear in some circumstances, like buffer overflow) and print an error.
Default is not mandatory, but it always good to have it.
The code is ideally, but our life is not, and there isn't any harm in putting in a protection there. It will also help you debugging if any unexpected thing happens.
Yes, the above code is valid.
If the switch condition doesn't match any condition of the case and a default is not present, the program execution goes ahead, exiting from the switch without doing anything.
It's same like no if condition is matched and else is not provided.
default is not an mandatory in switch case. If no cases are matched and default is not provided, just nothing will be executed.
The syntax for a switch statement in C programming language is as follows:
switch(expression) {
case constant-expression :
statement(s);
break; /* optional */
case constant-expression :
statement(s);
break; /* optional */
/* you can have any number of case statements */
default : /* Optional */
statement(s);
}