Forums before death by AOL, social media and spammers... "We can't have nice things"
|    comp.lang.c    |    Meh, in C you gotta define EVERYTHING    |    243,242 messages    |
[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]
|    Message 241,423 of 243,242    |
|    David Brown to Janis Papanagnou    |
|    Re: bugprone-switch-missing-default-case    |
|    23 Oct 25 09:08:19    |
   
   From: david.brown@hesbynett.no   
      
   On 23/10/2025 04:39, Janis Papanagnou wrote:   
   > On 22.10.2025 17:25, David Brown wrote:   
   >> On 22/10/2025 15:56, Janis Papanagnou wrote:   
   >>> On 22.10.2025 13:44, Richard Harnden wrote:   
   >>>> On 22/10/2025 10:32, Janis Papanagnou wrote:   
   >>>>> On 22.10.2025 10:56, pozz wrote:   
   >>>>>>   
   >>>>>>> Switch statements without a default case can lead to unexpected   
   >>>>>>> behavior and incomplete handling of all possible cases. When a switch   
   >>>>>>> statement lacks a default case, if a value is encountered that does   
   >>>>>>> not match any of the specified cases, the program will continue   
   >>>>>>> execution without any defined behavior or handling.   
   >>>>>>   
   >>>>>> Maybe I misunderstood that sentence caused by my bad English. I knew   
   >>>>>> that in case the switch value is not present in any case inside the   
   >>>>>> switch, the program continues without doing anything (in the   
   >>>>>> switch) and   
   >>>>>> without any problem.   
   >>>>>>   
   >>>>>> int x = 3;   
   >>>>>> switch(x) {   
   >>>>>> case 1: printf("Hello");break;   
   >>>>>> case 2: printf("World");break;   
   >>>>>> }   
   >>>>>>   
   >>>>>> Will the program execution continue without any defined behaviour?   
   >>>>>   
   >>>>> Your program fragment is well defined.   
   >>>>>   
   >>>>> What the poster certainly tried to express was that in case you   
   >>>>> haven't implemented a complete list of all possible cases and   
   >>>>> also not provided a 'default' to catch all non-specified cases,   
   >>>>> then you might get in troubles with your program, probably by   
   >>>>> possible oversights, future extensions, new data, and whatnot.   
   >>>>>   
   >>>>> Personally I have the habit to always define a default branch,   
   >>>>> and even if that default is impossible to reach you'll find an   
   >>>>> error message (like "internal error with unexpected value...")   
   >>>>> generated at that place.   
   >>>>>   
   >>>> Use an enum, and the compiler will warn you ...   
   >>>   
   >>> Maybe. Although I don't recall that the "C"-compilers I formerly   
   >>> used checked enums as you've shown below. - But anyway...   
   >>>   
   >>> Enums don't help if you use and compare against (for example)   
   >>> characters that are (for example) got from an external source.   
   >>>   
   >>> char * cmds = "CMDQ"; // 'D' maybe added later   
   >>> char cmd;   
   >>> ...some n lines of code...   
   >>> ...get input cmd...   
   >>> ...optionally verify cmd with cmds...   
   >>> ...some more m lines of code...   
   >>> switch (cmd) {   
   >>> case 'C': ...;   
   >>> case 'M': ...;   
   >>> default: printf ("Error: uncaught cmd '%c'\n", cmd);   
   >>> }   
   >>>   
   >>> It's good to take precautions and define the 'default' case. YMMV.   
   >>>   
   >>   
   >> That's not "taking precautions". If the "...optionally verify cmd" part   
   >> does a good job, then the default line is worse than useless because it   
   >> is code that never runs. [...]   
   >   
   > Not sure what you expect in that line. I've had something like   
   > strchr (cmds, cmd) in mind. And the 'switch' is independent   
   > of that, so you could miss adding the switch branch of a later   
   > added command character.   
   >   
   > The point was that mistakes can be made, not only in the initial   
   > implementation but also if it gets extended later, and probably   
   > by other folks than the original implementer. I also gave a hint   
   > with "...some more m lines of code..." that such omissions may   
   > also be hard to spot.   
   >   
   > It is experience from professional real life projects that such   
   > things happen. And blaming anyone that he's not done "a good job"   
   > may be the appropriate diagnosis and important point if what you   
   > want is primarily to blame someone, but if you want software to   
   > get developed reliably, one element is to quickly spot the place   
   > of such omissions.   
   >   
      
   It is not about placing blame - it is about being careful to avoid mistakes.   
      
   As you said, and I agreed, YMMV, and the details will depend on the type   
   of project and type of development environment you have. There is a   
   difference if "... some more lines of code..." means three lines in the   
   same function, or three thousand lines over the course of five years and   
   ten different developers.   
      
   I am not against putting in extra checks to catch mistakes that are   
   realistic. I am against putting in extra checks by /habit/, which is   
   what you said in your first post in this branch. Habit implies lack of   
   thought and consideration for the context. Sometimes habits are good,   
   and help you avoid forgetting important things, but they can also be bad   
   because you avoid the thought and analysis that is appropriate, and you   
   can easily end up with something that looks "better" or "safer", but is   
   actually worse in many ways. And it can reduce the likelihood of using   
   better solutions (such as enumerated types with -Wswitch=error checking   
   to turn missing cases into hard compiler errors). Even just a couple of   
   comments at each part of the code "if you change this code, remember to   
   change that code to match" may be better than unnecessary default cases.   
      
   And I am against any code that will never run. Such code is untestable,   
   and can quickly become a maintenance pain - people who see it can be   
   left wondering what it is expected to do, and why it is there, and how   
   it should be changed when other code is changed. An unnecessary printf   
   that is never called can turn a simple and efficient function into a   
   bigger and slower one, and turn a "pure" function into one with   
   side-effects which can spoil code analysis, thread safety, and   
   optimisations.   
      
   So by all means add a default clause with an error printout if it is   
   realistic for someone to use the code incorrectly, or if you are   
   debugging. And certainly check for bad data if the data is coming from   
   outside (like user input). But don't do it as a "habit", don't do it if   
   the default case can never be triggered, don't do it if it would be   
   better to check the data in other ways, and don't do it if you can use   
   other techniques that catch potential problems earlier (like using   
   enumerations).   
      
   --- SoupGate-Win32 v1.05   
    * Origin: you cannot sedate... all the things you hate (1:229/2)   
|
[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]
(c) 1994, bbs@darkrealms.ca