Why does gcc throw an implicit-fallthrough warning? - c

Given the code:
#include <stdlib.h>
enum one {
A, B
};
enum two {
AA
};
int main(int argc, char *argv[])
{
enum one one = atoi(argv[1]);
enum two two = atoi(argv[2]);
if ((one != A && one != B) || two != AA)
return 1;
switch (one) {
case A:
switch (two) {
case AA:
return 2;
}
case B:
return 3;
}
return 0;
}
When I compile it using using gcc -Wimplicit-fallthrough test_fallthrough.c I get the following warning
test_fallthrough.c: In function 'main':
test_fallthrough.c:21:3: warning: this statement may fall through [-Wimplicit-fallthrough=]
21 | switch (two) {
| ^~~~~~
test_fallthrough.c:25:2: note: here
25 | case B:
| ^~~~
What is it trying to warn against and what can I do so that it does not warn (I would prefer to avoid adding comments such as /* Falls through. */)

Why does gcc throw an implicit-fallthrough warning?
Well, because it may fallthrough.
What is it trying to warn against
A fallthrough from case A into case B when two != AA.
what can I do so that it does not warn
On gcc lower then 7 use a comment, ie. one of the markers that disable the warning:
/* falls through */
On gcc above 7 you could use a attribute:
__attribute__((__fallthrough__));
On gcc above 10 you could use the attribute from C2x:
[[fallthrough]];
--
Note that if (one != A || one != B || two != AA) is not really checking anything, as one != A || one != B will always be true. I guess you meant to do like if ((one != A && one != B) || two != AA). Still the -Wimplicit-falthrough= warning is not taking that if into account anyway.

You're missing a break in the first switch statement, it may fallthrough to the sencond case, it can execute case A and afterwards Case B, hence the warning.
//...
switch (one)
{
case A:
switch (two)
{
case AA:
return 2;
}
break; //breaking case A removes the warning.
case B:
return 3;
}
//...
Side note:
Using argc to check if argv[1] and argv[2] are present is always a good idea.

Usually, compiler checks for a break statement after every case body, so that it can ensure the program flow (fallthrough) is not a mistake.
In your case, case A body does not have a break, letting the execution to continue for case B also, when the switch statement matches that of case A.
switch (one) {
case A:
switch (two) {
case AA:
return 2;
}
// <------ no break here, flow will continue, or fall-through to next case body
case B:
return 3;
}
return 0;
}

Related

Is there any better implementation for this switch case construct?

I'm working on an embedded system where a register hast to be accessed and after that to be incremented to achieve the result I'm looking for, since the machine is notifying and configured to react on my access and changing or not changing the flag. So the switch's argument has to be kept as it is, since it would otherwise change the behaving of the embedded system.
But there may occur a situation where I don't want to get any of the cases get invoked. But I still need to acces and increment the argument of the switch.
(More indepth I'm converting a sequence of analog values to digital values conversions step by step. The index is used to stay synchronized with the current conversion and relating it with the corresponding case to handle the figure correct. There may occur a state in which the index desynchronisizes to the current conversion so the sequence of conversions must be run through without any of the cases getting invoked (to prevent setting wrong data) untill the sequence is finished and the resynchroinisation can get performed)
The way I'm currently doing this is this:
switch (RunIndex++)/*RunIndex may only be accessed one time per execution
of this construct and has to be incremented in the same step. thats given.*/
{
if (RunIndexSyncedWithADCensured == false)
{
break;
}
case 0:
Case0RelatedData = SomeOperationsForCase0(RawData);
break;
case 1:
Case1RelatedData = SomeOperationsForCase1(RawData);
break;
case 2:
Case2RelatedData = SomeOperationsForCase2(RawData);
break;
default:
RunIndex = 0;
break;
}
This construct does the job but it looks like it is a bit controversial and I don't feel well by considering about committing this into productinal code.
So is there a better looking way to achieve the same, without the need of additional variables or assignements?
note:
Also it may be relevant, that this is in the first part of a interupt function consisting of 2 parts.
The first part handles what has to happen if() a conversion is finished. The second part, what has additional to be done if() this conversion also ended the sequence. So it is no option to simply return from the function without getting into the second part. and there is currently no loop structure where an if(...)break; may break out. (What is also the reason why I'm putting the if inside the switch scope, as it is at least by standard a valid way to break out.)
Firstly, the if() inside switch() will never be executed.
Consider the below code snippet:
#include <stdio.h>
int main(int argc, char *argv[])
{
int i = 2;
switch(i) {
if (i == 2) {
printf("I M HERE\n");
}
case 1:
printf("1\n");
break;
case 2:
printf("2\n");
break;
default:
printf("default\n");
break;
}
return 0;
}
For your code: you expect the string I M HERE to be printed. But that is not the case.
The output for the above code snippet is:
2
No statements before case/default(switch constructs): is executed inside switch
Now to answer for
I don't want to get any of the cases get invoked. But I still need to acces and increment the argument of the switch
Just move the if() outside to the switch().
if (RunIndexSyncedWithADCensured) {
switch (RunIndex++) {
case 0:
Case0RelatedData = SomeOperationsForCase0(RawData);
break;
/* Other cases here */
default:
RunIndex = 0;
break;
}
} else
RunIndex++;
Why not save the value first and then increment it and use the saved value in the switch? By the way this also includes two accesses, first to read the value from RunIndex and the second to increment it.
int runIndex = (RunIndex++);
if (RunIndexSyncedWithADCensured )
{
switch (runIndex)/*RunIndex may only be accessed one time per execution
of this construct and has to be incremented in the same step. thats given.*/
{
case 0:
Case0RelatedData = SomeOperationsForCase0(RawData);
break;
case 1:
Case1RelatedData = SomeOperationsForCase1(RawData);
break;
case 2:
Case2RelatedData = SomeOperationsForCase2(RawData);
break;
default:
RunIndex = 0;
break;
}
}
Since you are using adjacent index numbers, you could make an array of function pointers to replace the switch. That's what the optimizer will turn the switch into anyhow. So instead of your obscure switch, you get this:
if (RunIndexSyncedWithADCensured)
{
SomeOperationsForCase[RunIndex](RawData);
}
RunIndex++;
if (RunIndex > MAX)
{
RunIndex = 0;
}
Completely unrelated to the switch statement design: in case RunIndex is a sensitive volatile variable such as some hardware register, then you shouldn't use it directly in any form of computations. Make a copy of it:
volatile int RunIndex;
...
int index = RunIndex; // read from RunIndex
if (RunIndexSyncedWithADCensured)
{
SomeOperationsForCase[index](RawData);
}
index++;
if (index > MAX)
{
index = 0;
}
RunIndex = index; // write to RunIndex
This is standard practice for all such volatile variables.

Verify that all set values of an enum are distinct

I just recently found out that when setting values of variables of an enum, several variables can have the same value. For example, the following code is perfectly correct:
enum my_enum
{
A = 3,
B = 4,
C = 3,
D = 5
};
However, in my framework, I have to set manualy each variable, since it is used to communicate error codes to other systems. I cannot change the value of an error code without asking for the other teams to modify it as well.
I regrouped all error codes into an enumeration to be sure we do not reuse the same error code for different reasons (which was the case before). But now, nothing stops anyone to reuse the same value for different errors.
Is there a way I can make the compiler return an error if I assign the same value to different names in my enum?
I can compile with either gcc or clang.
A switch statement cannot have two cases with the same value. So you can have a switch somewhere. Make it with no default: case and gcc will warn you that a member of the enum is not handled in the switch statement if you add a new value. If two values of the enum are the same, compilation will fail.
Some examples:
typedef enum {
ERR_NONE = 0,
ERR_SAME = 0
} err_t;
volatile err_t e = ERR_NONE;
int main( int argc, char* argv[] )
{
switch( e )
{
case ERR_NONE:
break;
case ERR_SAME:
break;
}
return 0;
}
with gcc -Wall switch.c gives:
switch.c: In function 'main':
switch.c:16:9: error: duplicate case value
case ERR_SAME:
^
switch.c:13:9: error: previously used here
case ERR_NONE:
^
and...
typedef enum {
ERR_NONE = 0,
ERR_NEXT,
ERR_MISSING,
} err_t;
volatile err_t e = ERR_NONE;
int main( int argc, char* argv[] )
{
switch( e )
{
case ERR_NONE:
break;
case ERR_NEXT:
break;
}
return 0;
}
with gcc -Wall switch-missing.c gives:
switch-missing.c: In function 'main':
switch-missing.c:12:5: warning: enumeration value 'ERR_MISSING' not handled in switch [-Wswitch]
switch( e )
^

Strange switch's behaviour in c

I want the code below to print ok when user enters 1 or 3, or to print why otherwise.
Why, when user enters 3, the program prints why?
#include <stdio.h>
#include <conio.h>
int main(void){
int i;
clrscr();
scanf("%d", &i);
switch(i){
case (1||3):
printf("ok\n");
break;
default:
printf("why\n");
}
getch();
return 0;
}
case(1||3):
Will not work. If you want to say "1 or 3", write:
case 1 :
case 3 :
printf("ok");
break;
If you don't have break between cases, they flow from one into the next. Try it in the debugger.
Expression
1||3
has constant value 1. Operator || is the logical OR operator that according to the C Standard
3 The || operator shall yield 1 if either of its operands compare
unequal to 0; otherwise, it yields 0. The result has type int.
So if you enter 1 then code under the case label will be executed. Otherwise the code under the default label is executed.
In fact your switch statement looks like
switch(i)
{
case 1:
printf("ok");
break;
default:
printf("why");
}
Expression 1 || 3 will be calculated at compilation time and the compiler will generate code that will correspond to the label
case 1:
All case label expressions are evaluated at compilation time and instead of the expressions the compiler uses their results.
To achive the result you want you should either add one more case label or substitute the switch statement for a if-else statement. For example
switch(i)
{
case 1:
case 3:
printf("ok");
break;
default:
printf("why");
}
or
if( i == 1 || i == 3 )
{
printf("ok");
}
else
{
printf("why");
}
You want to learn the following paradigm for flow control:
switch(i)
{
case (1):
case (3):
printf("ok");
break;
default:
printf("why");
}
Where either 1 or 3 will fall through until the break.
1||3 => true... which is typically 0x1
Yet another solution:
printf( (i==1||i==3)?"ok":"why" );

C macros with opening and closing tags?

I just started reading this article about exception handling in c with the use of setjmp( jmp_buf ) and longjmp( jmp_buf, int ). So I basically build the linked list that uses the local variables from type xRecord and links it to the list. (Example 2) It works just fine. But in example 3 the steps get summarized into macros (XTRY and XEND). What irritates me most is that the actual switch statement of example 2 just "vanished" in 3.
Example 2:
#define DIVIDE_BY_ZERO -3
int SomeFunction(int a, int b)
{
if (b == 0) // can't divide by 0
XRaise(DIVIDE_BY_ZERO);
return a / b;
}
void main(void)
{
XRecord XData;
XLinkExceptionRecord(&XData);
switch (setjmp(XData.Context))
{
case 0: // this is the code block
{
int Result = SomeFunction(7, 0);
// continue working with Result
}
break;
case DIVIDE_BY_ZERO:
printf("a division by zero occurred\n");
break;
default:
printf("some other error occurred\n");
break;
case XFINALLY:
printf("cleaning up\n");
}
XUnLinkExceptionRecord(&XData);
}
Example 3:
void main(void)
{
XTRY
case XCODE: // this is the code block
{
int Result = SomeFunction(7, 0);
// continue working with Result
}
break;
case DIVIDE_BY_ZERO: // handler for a
specific exception
printf("a division by zero occurred\n");
break;
default: // default handler
printf("some other error occurred\n");
break;
case XFINALLY: // finally handler
printf("cleaning up\n");
XEND
}
My question is, how can I build these "opening and closing" macros?
If you compare the two examples, and keep in mind that C macros are simple text substitutions, what the macros should be is evident:
#define XTRY XRecord XData; \
XLinkExceptionRecord(&XData); \
switch (setjmp(XData.Context)) \
{
#define XEND } \
XUnLinkExceptionRecord(&XData);
Note the use of \ to allow the macro to span more than one line.
You may also want to have the macros open and close a new scope (by adding { and }), so that using the macros multiple in succession doesn't give an error due to multiple definitions of the variable XData. You can also use the do / while(0) trick to allow these macros to be placed directly inside if, for, etc. without issues.
Don't hide the {} this only causes trouble. With a C99 compliant compiler, you can hide local variables and some code that is executed before and after the block:
#define MY_BLOCK \
for (int once = 0; once < 1; ++once) \
for (XRecord XData = { 0 }; once < 1; ++once) \
for (XLinkExceptionRecord(&XData); (XUnLinkExceptionRecord(&XData), (once < 1)); ++once) \
switch (setjmp(XData.Context))
Benefit would be that you only need one macro instead of two, and the {} would clearly indicate the scope of the construct, even for your favorite editor.

What does "passing argument 2 of strcmp makes pointer from integer without a cast" error in C mean?

I am compiling my C code and am getting two errors:
warning:passing argument 2 of strcmp makes pointer from integer without a cast
and
warning: note: expected const char * but argument is of type int
This my main:
int main(int argc, char *argv[])
{
//check to make sure that the command line arguments are valid
if(argc!=3)
{
printf("invalid function call try again\n");
}
//else to choose the proper command
else
{
//reverse routine A
if(strcmp(argv[2],'a'||'A')==0) //line 138
{
reva(argv[1]);
}
//reverse routine B
else if(strcmp(argv[2],'b'||'B')==0) //line 143
{
revb(argv[1]);
}
//reverse routine C
else if(strcmp(argv[2],'c'||'C')==0) //line 148
{
revc(argv[1]);
}
//unacceptable command line argumant
else
{
printf("unacceptable command line argument for reverse routine try again:\n");
}
}
}
It means what it says. 'a'||'A' is an integer – specifically, it is the integer 1. The second argument of strcmp must be a string, not an integer.
You appear to intend to compare argv[2] to a and A. You need two different strcmp calls for that. Also, you need to use double, not single, quotes.
In "C", the '||' operator is a boolean 'or' operation, not a concatenation operation. Also, the use of apostrophes denotes a single character which basically 'char' type.
I think you want something like this (for line 148):
if (strcmp(argv[2], "C")==0 || (strcmp(argv[2], "c")==0) ...
or, if your C library supports it:
if (strcasecmp(argv[2], "C") == 0)
which is a case insensitive comparison.
I believe that your object here is to compare the command line argument (argv[2]) with the character (string) "C" or "c", ie you just if the user gave c or C at the command line.
The SO users have already offered an explanation. You need to use
(strcmp(argv[2], "C")==0 || (strcmp(argv[2], "c")==0)
in order to eliminate your warning.
However, this is not the optimal way to parse command line arguments in C. If your program is too complicated when parsing user input I would suggest to use the library "getopt". It is designed to help the user parse and analyze the input in a structured manner.
Here is a small code snipper
opt = getopt_long( argc, argv, optString, longOpts, &longIndex );
while( opt != -1 ) {
switch( opt ) {
case 'I':
globalArgs.noIndex = 1; /* true */
break;
case 'l':
globalArgs.langCode = optarg;
break;
case 'o':
globalArgs.outFileName = optarg;
break;
case 'v':
globalArgs.verbosity++;
break;
case 'h': /* fall-through is intentional */
case '?':
display_usage();
break;
case 0: /* long option without a short arg */
if( strcmp( "randomize", longOpts[longIndex].name ) == 0 ) {
globalArgs.randomized = 1;
}
break;
default:
/* You won't actually get here. */
break;
}
opt = getopt_long( argc, argv, optString, longOpts, amp;longIndex );
}
Please search some documents (or the linux man pages) for getopt and getopt_long. Here is an example from GNU.

Resources