148

Our organization has a required coding rule (without any explanation) that:

if … else if constructs should be terminated with an else clause

Example 1:

if ( x < 0 )
{
   x = 0;
} /* else not needed */

Example 2:

if ( x < 0 )
{
    x = 0;
}
else if ( y < 0 )
{
    x = 3;
}
else    /* this else clause is required, even if the */
{       /* programmer expects this will never be reached */
        /* no change in value of x */
}

What edge case is this designed to handle?

What also concerns me about the reason is that Example 1 does not need an else but Example 2 does. If the reason is re-usability and extensibility, I think else should be used in both cases.

artless noise
  • 21,212
  • 6
  • 68
  • 105
Van Tr
  • 5,889
  • 2
  • 20
  • 44
  • 32
    Maybe ask your company for the reason and benefit. At first glance, it forces the programmer to think about it and add a comment "no action required". Same reasoning behind (and at least as controversial as) Java's checked exceptions. – Thilo Jan 28 '16 at 05:18
  • Do you mean either if or else if get execute. You also want to execute the else part. – Crazy Developer Jan 28 '16 at 05:19
  • 33
    Example 2 is actually a good example for where an `assert(false, "should never go here")` might make sense – Thilo Jan 28 '16 at 05:21
  • @Thilo yes, I've asked and have no good answers that's why I asked in stackoverflow. Before put the question here, I've investigated the problem too but didn't find any make sense reason. – Van Tr Jan 28 '16 at 05:24
  • 2
    Our organization has similar rules but not quite this granular. The purpose in our case is two-fold. First, code consistency. Second, no loose strings / readability. Requiring the else, even when un-needed, adds clarity to the code even when its not documented. Requiring an else is something I've done in the past, even when not needed, just to make sure I've accounted for all possible results in the app. – LuvnJesus Jan 28 '16 at 05:25
  • 5
    You could always defeat if with `if (x < 0) { x = 0; } else { if (y < 0) { x = 3; }}`. Or you could just follow such rules, many of which are foolish, simply because you are required to. – Jim Balter Jan 28 '16 at 05:34
  • Example 2: if X is 1 it will go to else, if y is 1 it will go to else. Ideally you would only test the same variable example if x < 0 then x is under 0, elseif x > 0 then x is over 0, else (otherwise) x is 0. – RoMEoMusTDiE Jan 28 '16 at 06:11
  • For example 1: even if you see only an if without an else the value of the variable as initialized is already your else statement. Example: y="over 0"; if x < 0 then y="under 0"; print y; - so if x is -1 this will print under 0, if x is 1 this will print over 0. – RoMEoMusTDiE Jan 28 '16 at 06:18
  • Because it doesn't matter how well you code, and what your requirements are, someday that else is going to be needed. In 5 or 10 years time it's going to happen, and that else (or default) will save your life. – RedSonja Jan 28 '16 at 08:19
  • @Thilo Not simply checked exceptions, but when an exception which should be unchecked is made checked. – Malcolm Jan 28 '16 at 09:41
  • @Thilo `assert(false, "should never go here")` causes warning C4002 (too many macro argument) in Visual Studio 2015. I'd use `&&`. IMHO C++11's `static_assert` adds to the confusion. – jingyu9575 Jan 28 '16 at 10:33
  • We use guard clauses here so... else is really for very very specific cases and the recommendation is that it be avoided – SparK Jan 28 '16 at 14:05
  • I'm sure I answered this question about 5 years ago. – Hot Licks Jan 29 '16 at 12:56
  • (The answer is that you don't need it if you never make a mistake. And if the code is never edited later, by a different person. Skilled programmers do this without being ordered, because they know (having learned from experience) that it's a good idea.) – Hot Licks Jan 29 '16 at 12:59
  • @HotLicks so could you please give your answer once more time ? – Van Tr Jan 29 '16 at 14:58
  • 3
    @Thilo I'm a bit late, but still nobody has caught the mistake: There is no indication that the else should never happen, only that it should have no side effects (which seems normal when doing `< 0` checks), so that assert is going to crash the program on what is probably the most common case where values are in expected bounds. – Loduwijk Nov 14 '18 at 15:17
  • @Aaron good point, at least for Example One. Example Two does say "the programmer expects this never to be reached". Either way, having something there (even just the comment as per company coding style) is a good thing. – Thilo Nov 15 '18 at 07:23

13 Answers13

160

As mentioned in another answer, this is from the MISRA-C coding guidelines. The purpose is defensive programming, a concept which is often used in mission-critical programming.

That is, every if - else if must end with an else, and every switch must end with a default.

There are two reasons for this:

  • Self-documenting code. If you write an else but leave it empty it means: "I have definitely considered the scenario when neither if nor else if are true".

    Not writing an else there means: "either I considered the scenario where neither if nor else if are true, or I completely forgot to consider it and there's potentially a fat bug right here in my code".

  • Stop runaway code. In mission-critical software, you need to write robust programs that account even for the highly unlikely. So you could see code like

    if (mybool == TRUE) 
    {
    } 
    else if (mybool == FALSE) 
    {
    }
    else
    {
      // handle error
    }
    

    This code will be completely alien to PC programmers and computer scientists, but it makes perfect sense in mission-critical software, because it catches the case where the "mybool" has gone corrupt, for whatever reason.

    Historically, you would fear corruption of the RAM memory because of EMI/noise. This is not much of an issue today. Far more likely, memory corruption occurs because of bugs elsewhere in the code: pointers to wrong locations, array-out-of-bounds bugs, stack overflow, runaway code etc.

    So most of the time, code like this comes back to slap yourself in the face when you have written bugs during the implementation stage. Meaning it could also be used as a debug technique: the program you are writing tells you when you have written bugs.


EDIT

Regarding why else is not needed after every single if:

An if-else or if-else if-else completely covers all possible values that a variable can have. But a plain if statement is not necessarily there to cover all possible values, it has a much broader usage. Most often you just wish to check a certain condition and if it is not met, then do nothing. Then it is simply not meaningful to write defensive programming to cover the else case.

Plus it would clutter up the code completely if you wrote an empty else after each and every if.

MISRA-C:2012 15.7 gives no rationale why else is not needed, it just states:

Note: a final else statement is not required for a simple if statement.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • 2
    [Attack of the](https://blogs.oracle.com/ksplice/entry/attack_of_the_cosmic_rays1) [Cosmic rays](http://www.cs.toronto.edu/~bianca/papers/sigmetrics09.pdf)! (+1) – Theraot Jan 28 '16 at 09:17
  • Unfortunately, if the memory really did get corrupted, it won't hit the else clause... it'll cause run-time errors when the comparison is performed. – Nelson Jan 28 '16 at 10:07
  • 3
    @Nelson Umm... yes, no, maybe? That assumption is highly system-specific. It seems you are assuming code is executed from RAM? Running code from RAM is very questionable practice for any embedded system, mission-critical or not. – Lundin Jan 28 '16 at 10:10
  • 6
    If memory is corrupted I expect it to wreck much more than just mybool, including maybe the checking code itself. Why don't you add another block that verifies that your `if/else if/else` compiled to what you expect? And then one more to verify previous verifier as well? – Oleg V. Volkov Jan 28 '16 at 11:14
  • 3
    Surely if a variable is somehow "corrupt" either the comparison will fail spectacularly or it will force the result into true or false based on whatever comparison rules are used? – Lilienthal Jan 28 '16 at 11:35
  • 55
    Sigh. Look guys, if you have absolutely no other experience beyond desktop programming, there's no need to make know-it-all comments about something you obviously have no experience of. This always happens when defensive programming is discussed and a PC programmer stops by. I added the comment "This code will be completely alien to PC programmers" for a reason. **You do not program safety-critical software to run on RAM-based desktop computers**. Period. The code itself will reside in flash ROM with ECC and/or CRC checksums. – Lundin Jan 28 '16 at 12:13
  • 3
    Well, I guess the compiler is prohibited from any optimization, because otherwise it might come to the conclusion that `mybool` cannot ever be anything but `TRUE` or `FALSE`. – Deduplicator Jan 28 '16 at 14:08
  • 7
    @Deduplicator Indeed (unless `mybool` has a non-boolean type, as was the case back before C got its own `bool`; then the compiler wouldn't make the assumption without additional static analysis). And on the subject of 'If you write an else but leave it empty it means: "I have definitely considered the scenario when neither if nor else if are true".': My first reaction is to assume the programmer forgot to put code in the else block, otherwise why have an empty else block just sitting there? An `// unused` comment would be appropriate, not just an empty block. – JAB Jan 28 '16 at 14:12
  • 1
    @Deduplicator That was actually the reason why I used "mybool" and TRUE/FALSE in the example, rather than `bool`, `true` and `false`. Assuming "mybool" is some old, home-brewn boolean type based on enums or similar. – Lundin Jan 28 '16 at 14:18
  • 7
    @JAB Yes, the `else` block needs to contain some sort of comment if there is no code. Common practice for empty `else` is a single semicolon plus a comment: `else { ; // doesn't matter }`. As there is no reason why anyone would otherwise just type an indented, single semi colon on a line of its own. Similar practice is sometimes used in empty loops: `while(something) { ; // do nothing }`. (code with line breaks, obviously. SO comments don't allow them) – Lundin Jan 28 '16 at 14:21
  • @Lundin you have great an answer but like I mentioned in question, why in Example 1 not need else. Because as you answered (which focus on Example 2), else is for corruption case and the code in Example 1 can corrupt like Sample 2 or any other codes in Embedded system ,right ? – Van Tr Jan 28 '16 at 15:28
  • @TrieuTheVan I tried to answer that question with an edit. – Lundin Jan 28 '16 at 15:43
  • 5
    I'd like to note, that this sample code with two IFs and else can go to else even in usual desktop software in multi-threaded environments, so value of mybool could be changed just in between – Iłya Bursov Jan 28 '16 at 15:50
  • @Lundin thanks, I'm investigating more about this. About the case of corruption, could you give me a existed article or science information that have example about that (the case 'my bool' differ to both 'true' and 'false' )? – Van Tr Jan 28 '16 at 15:55
  • @Lundin or should I make a question for your example code, maybe people could show many cases that the else case could be covered – Van Tr Jan 28 '16 at 15:57
  • @Lundin after spend time investigating I think that you answer is great and I accept it. But like I said in above comment, I glad to have articles that have example about the corruption case. – Van Tr Jan 29 '16 at 00:20
  • I would strongly argue that you *do* need the final else. Without it, it's easy for someone to come along later, monkey with the structure of several nested *if* statements, and cause the *else* statements to become improperly associated. – Hot Licks Jan 29 '16 at 13:02
  • @JAB: to be a little more precise, what is more important is that C has its own `_Bool`, which is a type with specified behaviour, e.g. values assigned to it are forced to `0` or `1`, while `bool` is a macro in `` which the programme is free to undefine or redefine. – PJTraill Feb 03 '16 at 14:48
  • 1
    Is there a reason not to put an `assert( false )` in the empty else-block (if appropriate)? That would document the expectation of it never happening, and help catch errors while debugging. – Raoul Steffen Feb 04 '16 at 09:15
  • 2
    @RaoulSteffen In safety-critical software, you allow no debug code at all to remain in the production build. So things like `assert` will just be problematic. It is better to implement the error handler for the actual product and then use that one. Besides, `assert` doesn't really make sense in embedded systems since there is usually nothing like "standard error streams" available. – Lundin Feb 04 '16 at 09:22
  • I would expect assertfail() to set the reset pin in an embedded environment. – Joshua May 04 '16 at 20:57
  • @Lundin wrote "no reason anyone would type a single indented semi colon on a line by itself" I used to do that long ago. "Just a semi-colon? Obviously it means you want nothing to happen there." Now, I'll try to pull something out of the branch's parenthesis and into the body. If there is nothing to pull out for some reason, then I would now leave a comment ("; // do nothing"). But that does not change what I did once upon a time; so yes, I did have a reason, and I probably (unfortunately) left too many instances of lonely ';' in legacy code. – Loduwijk Nov 14 '18 at 15:37
  • @Lundin As for debug code in safety-critical production code: is that actually part of the suggestion in the quoted guidelines as well or is that just the opinion of the teams you worked with? I have worked with safety-critical systems before, and think we had debug code left. Maybe not in the actual safety-critical section, but in other sections of the same program - is there a distinction for that in the guidelines? – Loduwijk Nov 14 '18 at 15:41
  • 1
    @Lundin While I understand you are just quoting guidelines and you probably are not responsible for them, still: I have always found it silly to use memory corruption as a reason for any production code (short of things like memory testing software, obviously). My reason for dismissing such checks as unnecessary is that you are only checking a small subset of the memory and only for a small subset of time. Even if you do have a memory corruption, adding in the example code probably won't help. It is a mostly-false sense of security. – Loduwijk Nov 14 '18 at 15:47
  • 1
    @Aaron "No debug code" basically means no left-overs from internal testing. That's banned by multiple standards, not only MISRA-C. If you implement a full-blown error handler system, that's of course fine, as it is then part of the application and not something that potentially ended up in the source by accident. Also, there is no such thing as "safety-critical section" of a firmware, if all is executed by the same MCU. A bug in one part of the program could cause another part to go haywire. Meaning that the whole program is either safety-critical or it is not, period. – Lundin Nov 14 '18 at 15:53
  • 1
    @Aaron Or for memory testing, as the answer mentions: "Far more likely, memory corruption occurs because of bugs elsewhere in the code: pointers to wrong locations, array-out-of-bounds bugs, stack overflow, runaway code etc." And then of course on these systems, the actual code is always executed from flash and not RAM. A PC programmer would not understand the distinction, since they always load the program itself in RAM, and therefore they go "but if the RAM is corrupt, your program can execute any nonsense op code" which isn't true on a MCU executing code from NVM flash. – Lundin Nov 14 '18 at 15:57
  • 2
    @Lundin I appreciate the distinction of where the code is being executed from, but that still does not dismiss the concern that if there is memory corruption, for whatever reason (bugs, heavy EM interference, the butterfly effect, a local but microscopic black hole passing through... whatever), the example `if/else if/else` check is still not likely to catch it, even if it is only variable data in RAM. There are many other variables in RAM, many of which you cannot so easily check for corruption (ints, pointers, floats, etc.) without redundant memory (which makes such checks pointless anyway). – Loduwijk Nov 14 '18 at 18:14
  • 1
    Or, for an analogy, checking that variable because it might be corrupt, when there are so many other variables that could be corrupt without being detected, is like installing a camera to watch your windows facing the baseball park to see if the window is broken but only installing 1 such camera and positioning it to observe only 1 window out of the 40 windows facing the park and equally at risk. If you are truly concerned about memory corruption enough to check for it, have a redundant variable to check against, as that would be far more likely to catch most forms of corruption. – Loduwijk Nov 14 '18 at 18:21
  • @Aaron This goes back to the days where RAM - including MCU peripheral memory mapped registers - were not reliable at all. They would then have to be continuously refreshed from NVM. The practice lives on and it is still good practice in a way, since NVM is most often more reliable than RAM. But mostly it is there to detect bugs and runaway code. If you ever implement proper defensive programming with a proper error handler, you'll notice how nice it is. Because the most notable effect is that your own program starts to report your own bugs back to you, often early on in the design stage. – Lundin Nov 15 '18 at 15:26
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/183740/discussion-between-aaron-and-lundin). – Loduwijk Nov 15 '18 at 17:14
  • @Lundin please tell me how you're able to presume "you are assuming code is executed from RAM" by just reading "it'll cause run-time errors when the comparison is performed" said by Nelson. These two sentences seem irrelevant to me – Andy Lin Nov 25 '20 at 05:59
  • @AndyLin "It seems you are assuming code is executed from RAM?" is a question, supposedly because the other person was potentially assuming that the program itself got corrupted. – Lundin Nov 25 '20 at 07:20
  • @Lundin Does program in somewhere other than RAM get corrupted? It seems you consider program got corrupted only happens in RAM. – Andy Lin Nov 25 '20 at 09:43
  • 1
    @AndyLin Yes it can be corrupted in flash, but then for different reasons than bugs or EMI. Instead it would get corrupted by flash erase/write cycle wear and data retention. Safety MCUs deal with this through hardware support by something called ECC, other MCUs by CRC32. Sometimes data in flash is also stored in 2 identical "mirror" segments. Hence the comment "The code itself will reside in flash ROM with ECC and/or CRC checksums". – Lundin Nov 25 '20 at 09:47
63

Your company followed MISRA coding guidance. There are a few versions of these guidelines that contain this rule, but from MISRA-C:2004:

Rule 14.10 (required): All if … else if constructs shall be terminated with an else clause.

This rule applies whenever an if statement is followed by one or more else if statements; the final else if shall be followed by an else statement. In the case of a simple if statement then the else statement need not be included. The requirement for a final else statement is defensive programming. The else statement shall either take appropriate action or contain a suitable comment as to why no action is taken. This is consistent with the requirement to have a final default clause in a switch statement. For example this code is a simple if statement:

if ( x < 0 )
{
 log_error(3);
 x = 0;
} /* else not needed */

whereas the following code demonstrates an if, else if construct

if ( x < 0 )
{
 log_error(3);
 x = 0;
}
else if ( y < 0 )
{
 x = 3;
}
else /* this else clause is required, even if the */
{ /* programmer expects this will never be reached */
 /* no change in value of x */
}

In MISRA-C:2012, which supersedes the 2004 version and is the current recommendation for new projects, the same rule exists but is numbered 15.7.

Example 1: in a single if statement programmer may need to check n number of conditions and performs single operation.

if(condition_1 || condition_2 || ... condition_n)
{
   //operation_1
}

In a regular usage performing a operation is not needed all the time when if is used.

Example 2: Here programmer checks n number of conditions and performing multiple operations. In regular usage if..else if is like switch you may need to perform a operation like default. So usage else is needed as per misra standard

if(condition_1 || condition_2 || ... condition_n)
{
   //operation_1
}
else if(condition_1 || condition_2 || ... condition_n)
{
  //operation_2
}
....
else
{
   //default cause
}

Current and past versions of these publications are available for purchase via the MISRA webstore (via).

Community
  • 1
  • 1
Embedded C
  • 1,448
  • 3
  • 16
  • 29
  • 2
    Thank, your answer is all the content of Misra rule, but I expect a answer for my confuse in edit part of the question. – Van Tr Jan 28 '16 at 05:43
  • @TrieuTheVan i have updated my answer hope it will satisfy the need – Embedded C Jan 28 '16 at 05:57
  • 2
    Good answer. Out of curiosity, do those guides say anything about what to do if you expect the `else` clause to be unreachable? (Leave off the final condition instead, throw an error, perhaps?) – jpmc26 Jan 28 '16 at 07:24
  • 17
    I'm going to down vote for plagiarism and links that violate copyright. I'll edit the post so that it becomes clearer what's your words and what's MISRA's words. Initially this answer was nothing but a raw copy/paste. – Lundin Jan 28 '16 at 08:00
  • 1
    @Lundin I accept it was copy/paste of the misra's coding guidance. Check the edits of the question and edits of my answer it will make u to understand better. Initially question was blank then it is edited. As per the question i am editing my answe. Any how thanks for ur edit – Embedded C Jan 28 '16 at 08:48
  • 9
    @TrieuTheVan: Questions must not be *moving targets*. Make sure your question is complete *before* you post it. – T.J. Crowder Jan 28 '16 at 11:00
  • @T.J.Crowder I didn't moving target, I just didn't mention enough and clearly my confusion. Thank for reminding. – Van Tr Jan 28 '16 at 11:01
  • So using `if(…) { … } else if(…) { … } else { /* meaningless comment */ }` is better than using `if(…) { … } else if(…) { … } /* meaningless comment */ `? – Holger Jan 28 '16 at 14:41
  • 1
    @jpmc26 Nope, but the point of MISRA isn't to give you tight code, it's to give you safe code. Any compiler these days will optimise out unreachable code anyway, so there's no downside. – Graham Jan 28 '16 at 14:47
  • I have added a link to the document description on the MISRA site as well as a footnote describing where to obtain the document, which is available for purchase. I do not have a copy of the document myself and so cannot add page or further section numbers, I assume the included rule number will suffice. cc @Lundin – Jason C Jan 28 '16 at 14:47
  • 1
    @JasonC Well, you can't buy MISRA-C:2004 any longer, it is withdrawn in favour of MISRA-C:2012. The identical rule exists in 2012 too, but there it is rule number 15.7. We can't actually know if the OP's company implements 2004 or 2012, but the citation is taken from 2004. – Lundin Jan 28 '16 at 14:56
  • @Lundin I think you can purchase it. It's listed for £10 (PDF) or £40 (hard copy) on the shop page (about 1/3 the way down) and I just added qty 1 to my basket. I didn't go any further than that, though. It *is* marked as "for reference only" with a note that it is superseded by :2012. Good point about not knowing which version the company uses; I'll edit the answer again in a moment, save some readers from being misled. – Jason C Jan 28 '16 at 14:59
  • @JasonC Aha, even the 1998 version is still available. Regardless, the 2012 version is strongly recommended, as it fixed lots of issues and also supports C99. – Lundin Jan 28 '16 at 15:09
  • I have made the edit mentioned in my previous comment, as best as I could. – Jason C Jan 28 '16 at 16:45
  • @Graham But the issue I was asking about *is* about safe code. Do they say that it's safer to throw an error in an `else` block you expect to be unreachable, or do they say it's safer to leave off the final conditional check? – jpmc26 Jan 28 '16 at 17:26
  • 1
    @jpmc26 Most of MISRA-C isn't about throwing errors, it's about making the code readable and maintainable. The point of the final "else" isn't to throw an error if it gets somewhere it shouldn't (although you can do that), it's to explicitly tell your reviewers/maintainers/coworkers that you thought about this condition and you didn't just forget about it. So comments saying "Should never get here" aren't very useful - those comments should say "Should never get here *because*...". – Graham Jan 29 '16 at 09:41
  • 1
    @jpmc26 Also as far as throwing errors goes, it depends on the reason why you shouldn't get there. If you shouldn't get there because it's genuinely unreachable based on compile-time conditions above, then a comment is fine. If you shouldn't get there because that value is valid but shouldn't happen (e.g. null pointer checks), then bailing out is definitely in order, because you can't expect the system to continue sanely when it's got to some unexpected state. What actions you take will depend on the system - fly-by-wire has different failsafe requirements from Windows. :) – Graham Jan 29 '16 at 09:49
20

This is the equivalent of requiring a default case in every switch.

This extra else will Decrease code coverage of your program.


In my experience with porting linux kernel , or android code to different platform many time we do something wrong and in logcat we see some error like

if ( x < 0 )
{
    x = 0;
}
else if ( y < 0 )
{
    x = 3;
}
else    /* this else clause is required, even if the */
{       /* programmer expects this will never be reached */
        /* no change in value of x */
        printk(" \n [function or module name]: this should never happen \n");

        /* It is always good to mention function/module name with the 
           logs. If you end up with "this should never happen" message
           and the same message is used in many places in the software
           it will be hard to track/debug.
        */
}
rajuGT
  • 6,224
  • 2
  • 26
  • 44
Jeegar Patel
  • 26,264
  • 51
  • 149
  • 222
  • 5
    This is where `__FILE__` and `__LINE__` macros are a useful for making the source location easy to find if the message is ever printed. – Peter Cordes Jun 21 '18 at 00:21
9

Only a brief explanation, since I did this all about 5 years ago.

There is (with most languages) no syntactic requirement to include "null" else statement (and unnecessary {..}), and in "simple little programs" there is no need. But real programmers don't write "simple little programs", and, just as importantly, they don't write programs that will be used once and then discarded.

When one write an if/else:

if(something)
  doSomething;
else
  doSomethingElse;

it all seems simple and one hardly sees even the point of adding {..}.

But some day, a few months from now, some other programmer (you would never make such a mistake!) will need to "enhance" the program and will add a statement.

if(something)
  doSomething;
else
  doSomethingIForgot;
  doSomethingElse;

Suddenly doSomethingElse kinda forgets that it's supposed to be in the else leg.

So you're a good little programmer and you always use {..}. But you write:

if(something) {
  if(anotherThing) {
    doSomething;
  }
}

All's well and good until that new kid makes a midnight modification:

if(something) {
  if(!notMyThing) {
  if(anotherThing) {
    doSomething;
  }
  else {
    dontDoAnything;  // Because it's not my thing.
  }}
}

Yes, it's improperly formatted, but so is half the code in the project, and the "auto formatter" gets bollixed up by all the #ifdef statements. And, of course, the real code is far more complicated than this toy example.

Unfortunately (or not), I've been out of this sort of thing for a few years now, so I don't have a fresh "real" example in mind -- the above is (obviously) contrived and a bit hokey.

Hot Licks
  • 47,103
  • 17
  • 93
  • 151
7

This, is done to make the code more readable, for later references and to make it clear, to a later reviewer, that the remaining cases handled by the last else, are do nothing cases, so that they are not overlooked somehow at first sight.

This is a good programming practice, which makes code reusable and extend-able.

Ahmed Akhtar
  • 1,444
  • 1
  • 16
  • 28
7

I would like to add to – and partly contradict – the previous answers. While it is certainly common to use if-else if in a switch-like manner that should cover the full range of thinkable values for an expression, it is by no means guaranteed that any range of possible conditions is fully covered. The same can be said about the switch construct itself, hence the requirement to use a default clause, which catches all remaining values and can, if not otherwise required anyway, be used as an assertion safeguard.

The question itself features a good counter-example: The second condition does not relate to x at all (which is the reason why I often prefer the more flexible if-based variant over the switch-based variant). From the example it is obvious that if condition A is met, x should be set to a certain value. Should A not be met, then condition B is tested. If it is met, then x should receive another value. If neither A nor B are met, then x should remain unchanged.

Here we can see that an empty else branch should be used to comment on the programmer's intention for the reader.

On the other hand, I cannot see why there must be an else clause especially for the latest and innermost if statement. In C, there is no such thing as an 'else if'. There is only if and else. Instead, the construct should formally be indented this way (and I should have put the opening curly braces on their own lines, but I don't like that):

if (A) {
    // do something
}
else {
    if (B) {
        // do something else (no pun intended)
    }
    else {
        // don't do anything here
    }
}

Should any standard happen to require curly braces around every branch, then it would contradict itself if it mentioned "if ... else if constructs" at the same time.

Anyone can imagine the ugliness of deeply nested if else trees, see here on a side note. Now imagine that this construct can be arbitrarily extended anywhere. Then asking for an else clause in the end, but not anywhere else, becomes absurd.

if (A) {
    if (B) {
        // do something
    }
    // you could to something here
}
else {
    // or here
    if (B) { // or C?
        // do something else (no pun intended)
    }
    else {
        // don't do anything here, if you don't want to
    }
    // what if I wanted to do something here? I need brackets for that.
}

In the end, it comes down for them to defining precisely what is meant with an "if ... else if construct"

Ingo Schalk-Schupp
  • 843
  • 10
  • 26
  • 1
    There is *nothing* in MISRA that prevents you using `else if` - quite the contrary, Rules exist to support it! Disclaimer: Current MISRA C chairman ;-) – Andrew Mar 23 '22 at 05:25
  • 1
    Thank you for the clarification, sir! I have now removed my false claims about MISRA. I checked my sources and found that the document I retained from my time in the automotive industry falsely claimed to constitute the original MISRA C standard from 2004, when in fact, it also included the in-house style guide, which was not marked as such. It was these rules that my original answer was based on. My apologies for the misrepresentation. – Ingo Schalk-Schupp Mar 23 '22 at 07:41
5

Logically any test implies two branches. What do you do if it is true, and what do you do if it is false.

For those cases where either branch has no functionality, it is reasonable to add a comment about why it doesn't need to have functionality.

This may be of benefit for the next maintenance programmer to come along. They should not have to search too far to decide if the code is correct. You can kind of Prehunt the Elephant.

Personally, it helps me as it forces me to look at the else case, and evaluate it. It may be an impossible condition, in which case i may throw an exception as the contract is violated. It may be benign, in which case a comment may be enough.

Your mileage may vary.

EvilTeach
  • 28,120
  • 21
  • 85
  • 141
5

The basic reason is probably code coverage and the implicit else: how will the code behave if the condition is not true? For genuine testing, you need some way to see that you have tested with the condition false. If every test case you have goes through the if clause, your code could have problems in the real world because of a condition that you did not test.

However, some conditions may properly be like Example 1, like on a tax return: "If the result is less than 0, enter 0." You still need to have a test where the condition is false.

TheBick
  • 341
  • 1
  • 5
  • 12
4

Most the time when you just have a single if statement, it's probably one of reasons such as:

  • Function guard checks
  • Initialization option
  • Optional processing branch

Example

void print (char * text)
{
    if (text == null) return; // guard check

    printf(text);
}

But when you do if .. else if, it's probably one of reasons such as:

  • Dynamic switch-case
  • Processing fork
  • Handling a processing parameter

And in case your if .. else if covers all possibilities, in that case your last if (...) is not needed, you can just remove it, because at that point the only possible values are the ones covered by that condition.

Example

int absolute_value (int n)
{
    if (n == 0)
    {
        return 0;
    }
    else if (n > 0)
    {
        return n;
    }
    else /* if (n < 0) */ // redundant check
    {
        return (n * (-1));
    }
}

And in most of these reasons, it's possible something doesn't fit into any of the categories in your if .. else if, thus the need to handle them in a final else clause, handling can be done through business-level procedure, user notification, internal error mechanism, ..etc.

Example

#DEFINE SQRT_TWO   1.41421356237309504880
#DEFINE SQRT_THREE 1.73205080756887729352
#DEFINE SQRT_FIVE  2.23606797749978969641

double square_root (int n)
{
         if (n  > 5)   return sqrt((double)n);
    else if (n == 5)   return SQRT_FIVE;
    else if (n == 4)   return 2.0;
    else if (n == 3)   return SQRT_THREE;
    else if (n == 2)   return SQRT_TWO;
    else if (n == 1)   return 1.0;
    else if (n == 0)   return 0.0;
    else               return sqrt(-1); // error handling
}

This final else clause is quite similar to few other things in languages such as Java and C++, such as:

  • default case in a switch statement
  • catch(...) that comes after all specific catch blocks
  • finally in a try-catch clause
Khaled.K
  • 5,828
  • 1
  • 33
  • 51
2

Our software was not mission critical, yet we also decided to use this rule because of defensive programming. We added a throw exception to the theoretically unreachable code (switch + if-else). And it saved us many times as the software failed fast e.g. when a new type has been added and we forgot to change one-or-two if-else or switch. As a bonus it made super easy to find the issue.

holdfenytolvaj
  • 5,637
  • 1
  • 17
  • 10
2

Well, my example involves undefined behavior, but sometimes some people try to be fancy and fails hard, take a look:

int a = 0;
bool b = true;
uint8_t* bPtr = (uint8_t*)&b;
*bPtr = 0xCC;
if(b == true)
{
    a += 3;
}
else if(b == false)
{
    a += 5;
}
else
{
    exit(3);
}

You probably would never expect to have bool which is not true nor false, however it may happen. Personally I believe this is problem caused by person who decides to do something fancy, but additional else statement can prevent any further issues.

ST3
  • 8,826
  • 3
  • 68
  • 92
0

I'm currently working with PHP. Creating a registration form and a login form. I am just purely using if and else. No else if or anything that is unnecessary.

If user clicks submits button -> it goes to the next if statement... if username is less than than 'X' amount of characters then alert. If successful then check password length and so on.

No need for extra code such as an else if that could dismiss reliability for server load time to check all the extra code.

Porixify
  • 51
  • 9
  • 1
    This question was written with the 'mirsa' tag. It is automotive safety-critical. I don't think the PHP in question is for that type of application? – artless noise Mar 20 '22 at 19:31
0

As this question on boolean if/else if was closed as a duplicate. As well, there are many bad answers here as it relates to .

For a boolean, there are only two cases. In the boolean instance, following the MISRA recommendation blindly maybe bad. The code,

if ( x == FALSE ) {
    // Normal action
} else if (x == TRUE ) {
    // Fail safe
}

Should just be refactored to,

if ( x == FALSE ) {
    // Normal action
} else {
    // Fail safe
}

Adding another else increases cyclometric complexity and makes it far harder to test all branches. Some code maybe 'safety related'; Ie, not a direct control function that can cause an unsafe event. In this code, it is often better to have full testability without instrumentation.

For truly safety functional code, it might make sense to separate the cases to detect a fault in this code and have it reported. Although I think logging 'x' on the failure would handle both. For the other cases, it will make the system harder to test and could result in lower availability depending on what the second 'error handling' action is (see other answers where exit() is called).


For non-booleans, there may be ranges that are nonsensical. Ie, they maybe some analog variable going to a DAC. In these cases, the if(x > 2) a; else if(x < -2) b; else c; makes sense for cases where deadband should not have been sent, etc. However, these type of cases do not exist for a boolean.

artless noise
  • 21,212
  • 6
  • 68
  • 105
  • 1
    There is a subtle but very valid point to this answer... in C, `false` is `0` but `true` can have *any value* (it just is usually `1`) - eg the `` `isxxxx` functions return `non-zero` for true. So testing for `true` is unwise... – Andrew Mar 24 '22 at 07:27