I'm 99% sure this won't work but that remaining 1% is bothering me
int x;
//is this if statement
if(x == 1, 5, 7)
{
//do something here
}
//equivalent to this if statement
if((x == 1) || (x == 5) || (x == 7))
{
//do something here
}
No it's totally not equivalent.
if(x == 1, 5, 7)
calls the comma operator, which will effectively end up in the last value because of , has the lowest precedence:
if(7)
since unfolding with parenthesis should look like
if(((x == 1), 5), 7)
while
if((x == 1) || (x == 2) || (x == 7))
checks if x equals either 1, 2 or 7.
They are not equal. When you write it like
if(x == 1, 5, 7)
{
//do something here
}
it basically translates into
if(7)
{
//do something here
}
which will always be true in case the number in the condition block is a non-zero number.
Example 1:
int main()
{
int x=10;
if(x==1,5,7)
cout<<"hello"<<endl;
return 0;
}
Here, the output is "hello", because 7 is treated as a true boolean variable.
Example 2:
int main()
{
int x=10;
if(x==1,5,0)
cout<<"hello"<<endl;
return 0;
}
Here, there is no output because 0 is considered as a false boolean variable.
Regarding a faster solution discussed in the comment section of the OP, here's a 'fast' solution:
If you have a large number of constant comparisons to perform, a switch statement is faster than individual if(x == 1) statements as it is compiled to a branch-table (a kind of hashtable directly within program code, giving it O(1) lookup), however it's possible that existing compilers will already optimize if(x==1||x==2||x==3...) to a branch-table too.
bool xIsInSet = false;
switch( x ) {
case 0: case 1: case 2: case 3:
case 4: case 5: case 6: case 7: // add a case for each literal comparison
xIsInSet = true; // no `break` needed, there's only 1 case.
}
if( xIsInSet ) {
// do stuff
}
This can be inlined to a lambda which is invoked immediately to eliminate xIsInSet:
if( [&x]() -> bool {
switch(x) { case 0: case 1: case 2: case 3: return true; }
return false; }()
) {
// do stuff
}
Unfortunately C++11's variadic templates don't let us dynamically add case statements, and hacking it using a preprocessor #define is possible - if you don't mind using a metaprogramming library. A better alternative might be an inline #include of a file generated by your build script. What would be even neater would be a way to somehow #include the standard-output from another program (e.g. if we could do #include '.\generateCasesFor.sh 1 2 5 10 12', alas not yet).
Related
I have a question about good coding practices. I understand the differences between doing an if-else if and multiple ifs (that is, when a condition is met in an if-else if, the rest of the checks are skipped). I've found a piece of code along these lines:
if (A == 5) {
do_something();
} else if (B == 7) {
do_something_else();
}
I understand that this code won't check B == 7 if A == 5. The code works, so that means that B is only 7, if A is not 5, but I think this is just waiting to break when the code changes. What I would do is:
if (A == 5) {
do_something();
return or continue or break;
}
if (B == 7) {
do_something_else();
return or continue or break;
}
My question is, when I have multiple exclusive cases that depend on different, exclusive variables, what's the best way to tackle the flow control? I have the impression that the first code (with else ifs) depends a lot on other pieces of code to work, and that changes in other areas might break it. The second one seems to be a bit clunky. A switch could be a third option, but I would need to create another structure to hold the case and the logic to assign its value, and I think that it would be a bit clunky and counter-intuitive.
You asked about "exclusive" cases, but the issue with the conditions A == 5 and B == 7 is that they are not exclusive; they are independent.
For full generality you may need to test and handle all four cases:
if(A == 5) {
if(B == 7) {
/* case 1 */
} else {
/* case 2 */
}
} else {
if(B == 7) {
/* case 3 */
} else {
/* case 4 */
}
}
This is the notorious "bushy" if/else block. It's notorious because it can almost immediately become nearly impossible for a reader to follow, especially if the cases are involved, or more levels are introduced. (I think most style guides will tell you never to use an if/else tree that's 3 or more levels deep. I'd certainly say that.)
I have occasionally used these two alternatives:
(1) Fully decouple the cases:
if(A == 5 && B == 7) {
/* case 1 */
} else if(A == 5 && B != 7) {
/* case 2 */
} else if(A != 5 && B == 7) {
/* case 3 */
} else if(A != 5 && B != 7) {
/* case 4 */
} else {
/* can't happen */
}
The point here is to make it maximally clear to a later reader exactly which conditions go with cases 1, 2, 3, and 4. For this reason, you might as well list the last, else if(A != 5 && B != 7) case explicitly (as I've shown), even though by that point it's basically an "else".
(2) Contrive a "two level" switch. I can't say this is a common technique; it has a whiff of being "too clever", but it's robust and readable, in its way:
#define PAIR(b1, b2) (((b1) << 8) | (b2))
switch(PAIR(A == 5), (B == 7)) {
case PAIR(TRUE, TRUE):
/* case 1 */
break;
case PAIR(TRUE, FALSE):
/* case 2 */
break;
case PAIR(FALSE, TRUE):
/* case 3 */
break;
case PAIR(FALSE, FALSE):
/* case 4 */
break;
}
I wouldn't recommend this when the conditions are A == 5 and B == 7, because when you're down in the switch, it's not obvious what "TRUE" and "FALSE" mean, but sometimes, this sort of thing can read cleanly. It's also cleanly amenable to 3 or more levels of nesting, unlike "bushy" if/else trees, which as I said are notoriously unreadable.
The most robust way of programming this,
while avoiding the assumption that either A==5 or B==7 is to consider all the four cases:
if ((A == 5) && (B == 7))
{
do_somethingAB();
/* or */
do_somethingA();
do_somethingB();
} else if (A == 5)
{
do_somethingA();
} else if (B == 7)
{
do_somethingB();
} else
{
do_somethingNeither();
/* or
do nothing */
}
As I think you know, the two pieces of code are not equivalent. (They're equivalent IF they both contain "return or continue or break", which makes the question more interesting, but that's a different answer.)
In general, which one you choose (or how you choose to rewrite it) has to depend on precisely what you want the program to do.
When you write
if (A == 5) {
do_something();
} else if (B == 7) {
do_something_else();
}
you're additionally saying you want to do_something_else only if A is not equal to 5. That might be just what you want, or it might be a bug. If you wanted to achieve the same effect without an else, it would have to look like this:
if (A == 5) {
do_something();
}
if (A != 5 && B == 7) {
do_something_else();
}
The second piece of code you wrote in your question, on the other hand, has the potential to execute both do_something and do_something_else.
In general, it's best (clearest and least confusing) if all the conditions in an if/else chain test variations on the same condition, not some unusual mixture involving, for example, both A and B.
You use an if/else block when the alternatives are truly and deliberately exclusive, and when you want to emphasize this fact. You might choose to use separate if blocks (not chained with else) when the alternatives are not exclusive, or when they're only coincidentally or accidentally exclusive. For example, I have deliberately written code like
if(A == 5) {
do_something();
}
if(A != 5) {
do_some_unrelated_thing();
}
I might do this when the two things have nothing to do with each other, meaning that in some future revision of the program's logic, they might be not be exclusive after all. Or, I might do this if do_something is not a single like, but is a long, elaborate block, at the end of which I'm concerned that the reader might not have remembered why we were or weren't doing something, and that on the other hand we might want to do something else. For similar reasons, I've occasionally written
if(A == 5) {
do_something();
}
if(A == 5) {
do_some_unrelated_thing();
}
in the case that, again, the two things to be done had nothing to do with each other, and the reasons for doing them might diverge.
[This is now my third answer. The fact that I keep misreading your question, and failing to grasp the essential point you're asking about, suggests that maybe I shouldn't be answering at all.]
I think the essential point you're asking about concerns the case where the cases are independent, but you get the effect of an else due to the fact that each clause contains a control-flow statement which "goes out": a break, or a continue, or a return, or something like that.
In this specific case, my preference today would be not to use the else. When we write
if(A == 5) {
do_something();
return or continue or break;
}
if(B == 7) {
do_something_else();
return or continue or break;
}
it's clear that the two conditions have nothing to do with each other, other than that they're both cases that do something to "finish" the subtask being done, and leave the block of code that's responsible for performing that subtask.
When we write the two cases separately (without an else), we make clear not only that they're independent, but that they could be reordered, or that another case could be introduced in between them, etc.
But then again, could they be reordered? How likely is it that both cases A == 5 and B == 7 will both be true? And in that case, how important is it that do_something be done, as opposed to do_something_else? If the two cases can't be reordered, if it would be wrong to test B first and maybe do do_something_else, I suppose the explicit else is preferable, to tie the two cases together and make even more clear the requirement that A be tested first.
Like any question of style, the arguments for and against this sort of thing end up being pretty subjective. You're not likely to find a single, overwhelmingly convincing answer one way or the other.
One way to handle this is to use a do { ... } while (0); technique.
Here is your original code:
if (A == 5) {
do_something();
} else if (B == 7) {
do_something_else();
}
Doing else if on the same line is [IMO] a bit of a hack because it hides the true indentation:
if (A == 5) {
do_something();
}
else
if (B == 7) {
do_something_else();
}
Using the aformentioned technique, which I've used quite a lot is:
do {
if (A == 5) {
do_something();
break;
}
if (B == 7) {
do_something_else();
break;
}
} while (0);
This becomes even more evident when we increase the number of levels in the if/else ladder:
if (A == 5) {
do_something();
} else if (B == 7) {
do_something_else();
} else if (C == 9) {
do_something_else_again();
} else if (D == 3) {
do_something_for_D();
}
Once again, this is indented to:
if (A == 5) {
do_something();
}
else
if (B == 7) {
do_something_else();
}
else
if (C == 9) {
do_something_else_again();
}
else
if (D == 3) {
do_something_for_D();
}
Using the do/while/0 block, we get something that is simpler/cleaner:
do {
if (A == 5) {
do_something();
break;
}
if (B == 7) {
do_something_else();
break;
}
if (C == 9) {
do_something_else_again();
break;
}
if (D == 3) {
do_something_for_D();
break;
}
} while (0);
Note: I've been programming in c for 35+ years, and I've yet to find a case where a more standard use of do/while (e.g. do { ... } while (<cond>)) can't be replaced more cleanly/effectively with either a standard for or while loop. Some languages don't even have a do/while loop. Thus, I consider the do loop to be available for reuse.
Another use of do/while/0 is to allow things defined by a preprocessor macro to appear as a single block:
#define ABORTME(msg_) \
do { \
printf(stderr,"ABORT: %s (at line %d)\n",msg_,__LINE__); \
dump_some_state_data(); \
exit(1); \
} while (0)
if (some_error_condition)
ABORTME("some_error_condition");
This question already has answers here:
C++ Switch won't compile with externally defined variable used as case
(8 answers)
Closed 6 years ago.
Here x, y, z are integers but those are not known at start. During the running it will calculate the values of x, y, z. I want to use those values as case condition.
Is there any way to use those values in switch?
Instead of switch if I use if else loop, ho
id = 1;
switch(id){
case x:
//call some function
break;
case y:
//call some different function
break;
default:
//error
break;
}
No, the case labels need to be compile-time integral constants.
You will need to use conditional statements instead:
if (id == x) {
// ...
} else if (id == y) {
// ...
} else if (id == z) {
// ...
} else {
// "default case"
}
Consider also that x, y and z may not all be distinct, so the order of the statements matters. (But the order also matters for case labels in a switch if you fall through any of them.)
What you want is not supported (as pointed out by other answers). However, worse, it is not sensible and hence cannot be emulated in any way. This is because the cases in a switch are unique and their order insignificant (except in case of fall-through), so
switch(enum_object) {
case A: return foo<A>();
case B: return foo<B>();
default: return foo<C>();
}
and
switch(enum_object) {
default: return foo<C>();
case B: return foo<B>();
case A: return foo<A>();
}
gives the same code, but
if(id == run_time_value_A)
return foo<A>();
if(id == run_time_value_B)
return foo<B>();
return foo<C>();
is not the same as, say,
if(id == run_time_value_B)
return foo<B>();
if(id == run_time_value_A)
return foo<A>();
return foo<C>();
they differ if run_time_value_B==run_time_value_A.
As pointed out by n.m, Kerrek SB, and this SO answer, case labels need to be compile-time integral constants.
The answer of Kerrek SB shows the immediate and intuitive if - else if-cascade solution.
However, if you'd also like to make use of the break-functionality in switch-statements, then the following if - if - cascade as general pattern would apply:
bool isBreak = false;
if (id==x) {
...
isBreak = true;
}
if (!isBreak && id==y) {
...
}
if (!isBreak) {
...
}
Note that with this pattern you can express - in contrast to switch- also situations where more than one of the case-statements (denoted as ifs) match, as, e.g. when x == y.
So basically my switch case works but my professor says there are too many returns and "use a variable result, then return it at the end!"
so here is my code
int getMonthValue(){
switch(month){
case(1): //January
if(isLeapYear(year) == true)
return 6;
else
return 0;
case(2): // February
if(isLeapYear(year) == true)
return 2;
else
return 3;
case(3): //March
return 3;
case(4): //April
return 6;
case(5): //May
return 1;
case(6): //June
return 4;
case(7): //July
return 6;
case(8): //August
return 2;
case(9): //September
return 5;
case(10): //October
return 0;
case(11): //November
return 3;
case(12): //December
return 5;}
};
I dont see anything wrong with it, I am sure it could be written better. Would someone be able to show me a way to either format this in a more user friendly way? My professor also wanted me to use breaks in the switch instead, not sure why to use the break over return.
This is not good idea to use logical operators in your case. Use a array! This code is very well understood and it is very fast. And it is very easy to change the return value:
unsigned getMonthValue(unsigned month, unsigned year) {
const static unsigned ans[2][12] = {
// Jan F M A M J J A S O N Dec
{0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5 } //normal year
, {6, 2, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5 } //leap year
};
assert(month <= 12);
assert(month >= 1);
const size_t month_index = month - 1;
const size_t leap = isLeapYear(year) ? 1 : 0;
return ans[leap][month_index];
}
UPDATE
There is very useful link about this technic - Lookup_table. Thanks to Schwern!
Try this
int getMonthValue(int month, int year){
map<int,int> staticAnswers;
staticAnswers[3] = 3;
staticAnswers[4] = 6;
staticAnswers[5] = 1;
staticAnswers[6] = 4;
staticAnswers[7] = 6;
staticAnswers[8] = 2;
staticAnswers[9] = 5;
staticAnswers[10] = 0;
staticAnswers[11] = 3;
staticAnswers[12] = 5;
switch(month){
case(1): //January
if(isLeapYear(year) == true)
return 6;
else
return 0;
case(2): // February
if(isLeapYear(year) == true)
return 2;
else
return 3;
default:
return staticAnswers[month];
};
Here is how I would write it:
int
getMonthValue (int month, int year)
{
switch(month)
{
case 1: // January
if (isLeapYear(year))
return 6; // explanation here of why 6 is the right value
return 0;
case 2: // February
if (isLeapYear(year))
return 2; // explain why 2 is the right value
return 3;
case 3: return 3; // March
case 4: return 6; // April
case 5: return 1; // May
case 6: return 4; // June
case 7: return 6; // July
case 8: return 2; // August
case 9: return 5; // September
case 10: return 0; // October
case 11: return 3; // November
case 12: return 5; // December
}
}
I know many inexperienced programmers would object to the statements not being consistent. However—written this way—the statement structure exactly follows the logic. That is, the lexical structure reveals the logic.
A good thing about switch statement is that you are allowed to fall-through case statements, so this is allowed in C++:
switch (month) {
case 4:
case 7:
return 6;
case 9:
case 12:
return 5;
Which should reduce the amount of return statements but will change the readable order.
Another option, since you are checking for all values in range [1-12], would be to use an array, eg:
static const int values[] = { 3, 6, 1 ... };
if (month < 3) {
/* leap year check */
}
else
return values[month - 3]; // we subtract 3 to start from March
But this in the end should be mostly personal preference, so the suggestion given by the professor sounds like just something to nag you.
Your professor is strictly enforcing the "Single Entry, Single Exit" (SESE) rule of Structured Programming. All inputs come in as arguments. All output is via a single return statement at the end. No surprise returns in the middle of the routine. No globals. Minimal side effects. No gotos. It makes code easier to read when you don't have to carefully scan it for returns or calling gotos in the middle of a function.
This is a good rule of thumb. And at the time this was conceived, in the 1970s, this was a radical idea. Now it's just how you do things.
The problem, like many style rules, is when you strictly enforce the rule without considering why the rule exists; you can wind up with the opposite effect. Some of the answers here have illustrated that nicely. Style rules are necessarily simplified versions of reality and enumerating all the edge cases and exceptions is difficult. Gotta allow some wiggle room.
For a small routine like yours that does one very clear thing, fits on one page, and is one easy to read switch statement... just do multiple returns like you're doing. Storing a return value for the end would make it longer and more complicated defeating the point of the rule. And you avoid forgetting a break, a very common C pitfall.
The other good reason to violate SESE is early exit. Structured programming says to do this:
int some_function(int arg) {
int ret;
if( arg < 0 ) {
ret = arg;
}
else {
this is the real
meat and potatoes
of the function
and because of
that one simple
condition at the
top it all
is indented an
extra level
adding complexity
to the whole
function
ret = whatever;
}
return ret;
}
Every level of nesting adds complexity. Early exit avoids this unnecessary nesting by getting the simple cases out of the way at the top.
int some_function(int arg) {
if( arg < 0 ) {
return arg;
}
this is the real
meat and potatoes
of the function
which doesn't
have to be indented
an extra level
since we dealt with
all the simple cases
at the top
return whatever;
}
The extra return at the start doesn't significantly add complexity because it's in a predictable spot. It's only surprise returns in the middle of a large function that are a problem.
The other side of this is minuscule style arguments like this can distract from real problems. Your code has two much bigger problems, and I hope your prof called you on them.
Pass values into functions, don't use globals.
Your function takes no arguments. Instead month and year are globals. This is very bad style. It makes your program difficult to understand because anything can potentially effect anything. Instead, pass them in.
int getMonthValue( int month, int year ) {
...
}
Check your bounds.
The second problem is your function has no bounds checking. What if month is 0? 13? -50? 20398? It will fall through the switch statement and out the bottom of the function. The compiler should have warned you about this.
test.c:48:1: warning: control may reach end of non-void function [-Wreturn-type]
}
^
To solve this, unless you can think of a good reason not to, always put a default clause on switch.
switch(month) {
...all your regular cases...
default:
fprintf(stderr, "Month %d is out of range.\n", month);
exit(1);
}
Your professor is right, don't worry its all in the learning process
Try something like this:
int result = -1;
switch(month){
case 1: //January
if(isLeapYear(year) == true)
result = 6;
else
result = 0;
break;
case 2: // February
if(isLeapYear(year) == true)
result = 2;
else
result = 3;
break;
case 3: //March
result = 3;
break;
case 4: //April
result = 6;
break;
case 5: //May
result = 1;
break;
case 6: //June
result = 4;
break;
case 7: //July
result = 6;
break;
case 8 : //August
result = 2;
break;
case 9: //September
result = 5;
break;
case 10: //October
result = 0;
break;
case 11: //November
result = 3;
break;
case 12: //December
result = 5;
break;
}
return result;
Also don't use brackets in your cases it doesnt look clean at all.
I sometimes also choose to use brackets in my cases "{" and "}" although in this example its probably more appropiate not to. Weather or not using brackets is the best practice I do not know.
I am refeering to these brackets by the way "{" and "}"
Anyway thats a cleaner case statement, hope it helped.
a possible solution With the ternary operator!:
int getMonthValue()
{
return
month == 3 ? 3 :
month == 4 ? 6 :
month == 5 ? 1 :
month == 6 ? 4 :
month == 7 ? 6 :
month == 8 ? 2 :
month == 9 ? 5 :
month == 10 ? 0 :
month == 11 ? 3 :
month == 12 ? 5 :
month == 1 ? isLeapYear(year) ? 6 : 0 :
month == 2 && isLeapYear(year) ? 2 : 3 ;
}
When programming, I'm usually dealing with two sets of conditions combined together, like:
if (A && B){...}
else if (!A && B){...}
else if (A && !B){...}
else if (!A && !B){...}
It can also be resolved using nested if statements.
if (A){
if (B) {...}
else {...}
}
else {
if (B) {...}
else {...}
}
EDIT: Some new thoughts, what about I firstly evaluate both A and B and store as temporary variable (then do as the first approach) in case that the evaluation of A and B both have no side-effect?
So my question is there any performance difference between them and what about their readability?
I code in C++, if matters.
The two cases are not the same. In the second case, A and B will each be evaluated exactly once. In the first case, A and B will evaluated a number of times, depending upon their value.
While this almost certainly won't affect the optimization of the typical case, it will matter if A or B have side effects.
There's no way to predict which code generation strategy the compiler will choose in cases like that (and it can actually depend on surrounding context). This makes your question unanswerable in general case. One should normally expect the compiler to be smart enough to recognize the equivalence of both of your constructs (assuming they are indeed equivalent) and choose the most optimal one automatically.
The most optimal code generation strategy might be something else altogether, e.g.
// Assuming A and B are either 0 or 1
switch ((A * 2) + B) {
case 0: ...; break;
case 1: ...; break;
case 2: ...; break;
case 3: ...; break;
}
Just choose whatever makes your code more readable.
It's a hard question; honestly, I think everyone looks at this a little bit differently. As people have mentioned here it does not matter as a compiler should generate the same output for both (should! not necessarily will — it honestly depends on the code).
Yet, for example, let's look at this code:
int Nested(int a)
{
if(a > 0)
{
if( a > 1)
{
if( a % 2 == 0)
{
if( a % 10 == 4)
{
printf("a is valid");
return 1;
}
else
{
printf("a's last digit inst 4");
}
}
else
{
printf(" a is not odd");
}
}
else
{
printf(" a is not bigger than 1");
}
}
else
{
printf(" a is not bigger than 0");
}
return 0;
}
int NotNested(int a)
{
if(a <= 0)
{
printf(" a is not bigger than 0");
return 0;
}
if(a <= 1)
{
printf(" a is not bigger than 1");
return 0;
}
if(a % 2 != 0)
{
printf(" a is not odd");
return 0;
}
if( a % 10 != 4)
{
printf("a's last digit inst 4");
return 0;
}
printf("a is valid");
return 1;
}
I personally think that NotNested in my example is much more readable,
yet it's my personal opinion and both of these functions should do the same.
So yeah, in terms, of readability try to avoid nesting.
I have two variables
int a, b ;
a and b can have any of the values from 0-3 and there should be a couple of sentences for each condition based on values of a and b.
I used nested switches:
switch(a)
{
case go:
{
switch(b)
{
case go: {...}
...
case write: {...}
}
}
...
case 3:
{
...
}
}
Also I have an
enum
{
go = 0 ;
wait =1 ;
read = 2;
write =3 ;
}
I have a very big nested switch to check all the 4*4 =16 conditions
I would like to implement using question mark ? : operator
something like
(a=b==0) ? Do something ? Do something.
However I have multiple statements to do in each condition.
How do I do this using this ? : ternary operator?
Thanks in advance
You might instead want to consider flattening your 4 x 4 switch blocks into a single 16 way switch:
#define SELECT(a, b) ((a) * 4 + (b))
int select = SELECT(a, b);
assert(a >= 0 && a < 4); // sanity checking - make sure a and b are valid
assert(b >= 0 && b < 4);
switch (select)
{
case SELECT(0, 0):
// ...
break;
case SELECT(0, 1):
// ...
break;
case SELECT(0, 2):
// ...
break;
case SELECT(0, 3):
// ...
break;
case SELECT(1, 0):
// ...
break;
// ...
case SELECT(3, 3):
// ...
break;
}
Note that this works OK in both C and C++. It also works regardless of whether a and b are ints or enums (note that you can use actual enum labels in the SELECT macro - you don't need to use literal constants).