Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #394647 > unrolled thread

bugprone-switch-missing-default-case

Started bypozz <pozzugno@gmail.com>
First post2025-10-22 10:56 +0200
Last post2025-10-22 18:13 +0000
Articles 18 on this page of 38 — 11 participants

Back to article view | Back to comp.lang.c


Contents

  bugprone-switch-missing-default-case pozz <pozzugno@gmail.com> - 2025-10-22 10:56 +0200
    Re: bugprone-switch-missing-default-case Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2025-10-22 11:32 +0200
      Re: bugprone-switch-missing-default-case Richard Harnden <richard.nospam@gmail.invalid> - 2025-10-22 12:44 +0100
        Re: bugprone-switch-missing-default-case Thiago Adams <thiago.adams@gmail.com> - 2025-10-22 10:05 -0300
          Re: bugprone-switch-missing-default-case Kaz Kylheku <643-408-1753@kylheku.com> - 2025-10-22 18:22 +0000
            Re: bugprone-switch-missing-default-case David Brown <david.brown@hesbynett.no> - 2025-10-23 09:12 +0200
              Re: bugprone-switch-missing-default-case Thiago Adams <thiago.adams@gmail.com> - 2025-10-23 08:03 -0300
                Re: bugprone-switch-missing-default-case David Brown <david.brown@hesbynett.no> - 2025-10-23 17:06 +0200
                  Re: bugprone-switch-missing-default-case Thiago Adams <thiago.adams@gmail.com> - 2025-10-23 13:15 -0300
                    Re: bugprone-switch-missing-default-case bart <bc@freeuk.com> - 2025-10-23 17:46 +0100
                      Re: bugprone-switch-missing-default-case Thiago Adams <thiago.adams@gmail.com> - 2025-10-23 14:12 -0300
                    Re: bugprone-switch-missing-default-case David Brown <david.brown@hesbynett.no> - 2025-10-23 22:40 +0200
                      Re: bugprone-switch-missing-default-case scott@slp53.sl.home (Scott Lurndal) - 2025-10-23 20:51 +0000
                        Re: bugprone-switch-missing-default-case Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2025-10-23 16:21 -0700
                        Re: bugprone-switch-missing-default-case David Brown <david.brown@hesbynett.no> - 2025-10-24 08:59 +0200
                          Re: bugprone-switch-missing-default-case scott@slp53.sl.home (Scott Lurndal) - 2025-10-24 15:51 +0000
                      Re: bugprone-switch-missing-default-case tTh <tth@none.invalid> - 2025-10-23 23:57 +0200
                        Re: bugprone-switch-missing-default-case David Brown <david.brown@hesbynett.no> - 2025-10-24 09:22 +0200
                    Re: bugprone-switch-missing-default-case antispam@fricas.org (Waldek Hebisch) - 2025-10-23 23:23 +0000
                      Re: bugprone-switch-missing-default-case David Brown <david.brown@hesbynett.no> - 2025-10-24 09:53 +0200
        Re: bugprone-switch-missing-default-case David Brown <david.brown@hesbynett.no> - 2025-10-22 15:41 +0200
          Re: bugprone-switch-missing-default-case Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2025-10-22 16:05 +0200
            Re: bugprone-switch-missing-default-case David Brown <david.brown@hesbynett.no> - 2025-10-22 17:23 +0200
              Re: bugprone-switch-missing-default-case Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2025-10-23 04:54 +0200
                Re: bugprone-switch-missing-default-case David Brown <david.brown@hesbynett.no> - 2025-10-23 09:30 +0200
              Re: bugprone-switch-missing-default-case antispam@fricas.org (Waldek Hebisch) - 2025-10-23 22:40 +0000
          Re: bugprone-switch-missing-default-case Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2025-10-22 12:41 -0700
            Re: bugprone-switch-missing-default-case pozz <pozzugno@gmail.com> - 2025-10-23 08:47 +0200
              Re: bugprone-switch-missing-default-case Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2025-10-23 16:17 -0700
                Re: bugprone-switch-missing-default-case Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2025-10-23 19:13 -0700
            Re: bugprone-switch-missing-default-case David Brown <david.brown@hesbynett.no> - 2025-10-23 10:44 +0200
        Re: bugprone-switch-missing-default-case Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2025-10-22 15:56 +0200
          Re: bugprone-switch-missing-default-case David Brown <david.brown@hesbynett.no> - 2025-10-22 17:25 +0200
            Re: bugprone-switch-missing-default-case Janis Papanagnou <janis_papanagnou+ng@hotmail.com> - 2025-10-23 04:39 +0200
              Re: bugprone-switch-missing-default-case David Brown <david.brown@hesbynett.no> - 2025-10-23 09:08 +0200
            Re: bugprone-switch-missing-default-case Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2025-10-23 16:31 -0700
              Re: bugprone-switch-missing-default-case David Brown <david.brown@hesbynett.no> - 2025-10-24 10:09 +0200
    Re: bugprone-switch-missing-default-case Kaz Kylheku <643-408-1753@kylheku.com> - 2025-10-22 18:13 +0000

Page 2 of 2 — ← Prev page 1 [2]


#394652

FromDavid Brown <david.brown@hesbynett.no>
Date2025-10-22 15:41 +0200
Message-ID<10damv3$ku01$1@dont-email.me>
In reply to#394649
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?

Presumably you meant "without any undefined behaviour" ?  The code is 
fine - if no cases match and there is no default case, execution 
continues from the end of the switch statement.  Like most warnings, 
this is about a possible bug in the code - not a definite one.

>>
>> 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.

I don't think it is normally appropriate to add a default case unless 
you actually need it - code that exists but can never be reached is 
untestable and can be confusing to people reading the code.  But 
sometimes it can be useful to add a "default : printf("Internal 
error...");" for debugging, however.

In some code, I will have "default : __builtin_unreachable();" to 
improve code efficiency.


>>
> Use an enum, and the compiler will warn you ...
> 
> $ cat x.c
> #include <stdio.h>
> 
> enum x {A, B, C};
> 
> int main(void)
> {
>      enum x x = C;
> 
>      switch (x)
>      {
>          case A:
>              printf("A\n");
>              break;
> 
>          case B:
>              printf("B\n");
>              break;
>      }
> 
>      return 0;
> }
> 
> $ gcc -Wall x.c
> x.c: In function ‘main’:
> x.c:9:9: warning: enumeration value ‘C’ not handled in switch [-Wswitch]
>      9 |         switch (x)
>        |         ^~~~~~
> 
> 

gcc has a number of warning options regarding switches :

-Wimplicit-fallthrough=n
Warns when you have fall-through between cases, unless you add a 
[[fallthrough]] attribute, "// fallthrough" comment, or the like.  It is 
enabled by -Wextra.

-Wswitch
Warns when you have a switch on an enumerated type, and are missing an 
enumeration value and don't have a default case.  This is in -Wall.

-Wswitch-default
Warns when a switch does not have a default case.

-Wswitch-enum
Warns when you have a switch on an enumerated type, and are missing an 
enumeration value, even if you have a default case.



I think it is generally a good idea to use enumerated types when you are 
representing a number of possible options, rather than a plain "int" 
with "magic numbers" or individual #define constants.  Then "-Wswitch" 
(usually from "-Wall") or "-Wswitch-enum" is typically a good idea.

[toc] | [prev] | [next] | [standalone]


#394654

FromJanis Papanagnou <janis_papanagnou+ng@hotmail.com>
Date2025-10-22 16:05 +0200
Message-ID<10daob9$m3em$1@dont-email.me>
In reply to#394652
On 22.10.2025 15:41, David Brown 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?
> 
> Presumably you meant "without any undefined behaviour" ?  The code is
> fine - if no cases match and there is no default case, execution
> continues from the end of the switch statement.  Like most warnings,
> this is about a possible bug in the code - not a definite one.
> 
>>>
>>> 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.
> 
> I don't think it is normally appropriate to add a default case unless
> you actually need it

Yes I was saying that I want it; I "need" it once errors slip in and
such a message or error log immediately clears the issue! (You might
be excluding some "needs" from your repertoire of necessities, okay.)

> - code that exists but can never be reached is
> untestable and can be confusing to people reading the code.  But
> sometimes it can be useful to add a "default : printf("Internal
> error...");" for debugging, however.

This printf error message or log entry is what I suggested. It isn't
confusing because it even _documents_ what's the case here. Rather,
a missing default leaves the reader with an unnecessary uncertainty.
YMMV.

Janis

[toc] | [prev] | [next] | [standalone]


#394655

FromDavid Brown <david.brown@hesbynett.no>
Date2025-10-22 17:23 +0200
Message-ID<10dasso$nfjr$1@dont-email.me>
In reply to#394654
On 22/10/2025 16:05, Janis Papanagnou wrote:
> On 22.10.2025 15:41, David Brown 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?
>>
>> Presumably you meant "without any undefined behaviour" ?  The code is
>> fine - if no cases match and there is no default case, execution
>> continues from the end of the switch statement.  Like most warnings,
>> this is about a possible bug in the code - not a definite one.
>>
>>>>
>>>> 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.
>>
>> I don't think it is normally appropriate to add a default case unless
>> you actually need it
> 
> Yes I was saying that I want it; I "need" it once errors slip in and
> such a message or error log immediately clears the issue! (You might
> be excluding some "needs" from your repertoire of necessities, okay.)
> 
>> - code that exists but can never be reached is
>> untestable and can be confusing to people reading the code.  But
>> sometimes it can be useful to add a "default : printf("Internal
>> error...");" for debugging, however.
> 
> This printf error message or log entry is what I suggested. It isn't
> confusing because it even _documents_ what's the case here. Rather,
> a missing default leaves the reader with an unnecessary uncertainty.
> YMMV.
> 

Indeed YMMV.  But when I see a printf call that says something has gone 
horribly wrong, I wonder /how/ that could happen.  I don't put such 
statements into my code without it being a possible execution path.  I 
agree, of course, that a good error message here makes the code somewhat 
self-documenting in terms of what it does.  But it does nothing to help 
say how it happened to run.  A printf call that never runs is not free - 
it costs in many different ways, and should not be there unless it is 
worth those costs.

[toc] | [prev] | [next] | [standalone]


#394670

FromJanis Papanagnou <janis_papanagnou+ng@hotmail.com>
Date2025-10-23 04:54 +0200
Message-ID<10dc5cr$163j9$1@dont-email.me>
In reply to#394655
On 22.10.2025 17:23, David Brown wrote:
> On 22/10/2025 16:05, Janis Papanagnou wrote:
>> On 22.10.2025 15:41, David Brown 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?
>>>
>>> Presumably you meant "without any undefined behaviour" ?  The code is
>>> fine - if no cases match and there is no default case, execution
>>> continues from the end of the switch statement.  Like most warnings,
>>> this is about a possible bug in the code - not a definite one.
>>>
>>>>>
>>>>> 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.
>>>
>>> I don't think it is normally appropriate to add a default case unless
>>> you actually need it
>>
>> Yes I was saying that I want it; I "need" it once errors slip in and
>> such a message or error log immediately clears the issue! (You might
>> be excluding some "needs" from your repertoire of necessities, okay.)
>>
>>> - code that exists but can never be reached is
>>> untestable and can be confusing to people reading the code.  But
>>> sometimes it can be useful to add a "default : printf("Internal
>>> error...");" for debugging, however.
>>
>> This printf error message or log entry is what I suggested. It isn't
>> confusing because it even _documents_ what's the case here. Rather,
>> a missing default leaves the reader with an unnecessary uncertainty.
>> YMMV.
>>
> 
> Indeed YMMV.  But when I see a printf call that says something has gone
> horribly wrong,

"has gone horribly wrong"? - It says nothing like that. - As I already
said it's an effective measure to be able to quickly spot errors that
slipped in.

> I wonder /how/ that could happen. 

(In the world I live and worked in I saw mistakes and errors happen.)

> I don't put such
> statements into my code without it being a possible execution path. 

(Do what you prefer in your personal context. - I don't mind.)

> I
> agree, of course, that a good error message here makes the code somewhat
> self-documenting in terms of what it does. 

(Glad to hear you see and accept that.)

> But it does nothing to help say how it happened to run. 

??? - The example scenario will run. Just may have erroneous results
when triggering the case that isn't handled. With diagnostic records
you can quickly identify and fix it (usually in one of the QA test
cycles before you deliver the software).

> A printf call that never runs is not free -
> it costs in many different ways, and should not be there unless it is
> worth those costs.

(You're obviously a better discussion candidate for folks who count
bytes and microseconds, say, like bart. - The "costs" that matters
much more in professional software development are quality and time.)

Janis

[toc] | [prev] | [next] | [standalone]


#394675

FromDavid Brown <david.brown@hesbynett.no>
Date2025-10-23 09:30 +0200
Message-ID<10dclj6$1dnn6$3@dont-email.me>
In reply to#394670
On 23/10/2025 04:54, Janis Papanagnou wrote:
> On 22.10.2025 17:23, David Brown wrote:
>> On 22/10/2025 16:05, Janis Papanagnou wrote:

>> But it does nothing to help say how it happened to run.
> 
> ??? - The example scenario will run. Just may have erroneous results
> when triggering the case that isn't handled. With diagnostic records
> you can quickly identify and fix it (usually in one of the QA test
> cycles before you deliver the software).
> 

There may have been a misunderstanding here about what your various 
"..." lines before the switch statement did.  I understood them to be 
checking the input data for validity, in which case the default case is 
unnecessary and will not be run.  But if the switch itself is checking 
the input data, then the default case is an integral part of that check. 
  It's not an unnecessary or extra default added by habit, it's just 
normal usage.

>> A printf call that never runs is not free -
>> it costs in many different ways, and should not be there unless it is
>> worth those costs.
> 
> (You're obviously a better discussion candidate for folks who count
> bytes and microseconds, say, like bart. - The "costs" that matters
> much more in professional software development are quality and time.)
> 

As a professional software developer, costs matter - different kinds of 
costs, scaled differently in different situations.  Yes, developer costs 
matter.  So do run-time costs.  If developer costs are the only thing 
that matters and run-time costs do not, then why are you programming in 
C?  There can be a number of good reasons for choosing C over, say, 
Python, but run-time efficiency for at least part of the code is very 
often a major reason.

I work mainly on small-system embedded devices.  A printf is a very 
expensive operation in many ways.  I'll use it if it is the right thing 
to use, and not if is inappropriate.  For some of my systems, being 
slap-dash about printf's and the like means the code won't fit in the 
microcontroller's flash, and we need a new hardware design (at very 
significant developer cost).  Not long ago I wrote some code that had to 
run in less than a tenth of a microsecond - adding an extra printf, even 
if it was never called, would have added overhead to the function which 
would have exceeded the timing requirements.  Timing failures here would 
mean shoot-through of power transistors and blowing the boards.

Premature optimisation is the root of all evil, but premature 
pessimisation is not good either.  You have to know when code needs to 
be efficient, and pick different balances between developer costs and 
run-time costs according to the situation.


[toc] | [prev] | [next] | [standalone]


#394691

Fromantispam@fricas.org (Waldek Hebisch)
Date2025-10-23 22:40 +0000
Message-ID<10deata$1tetm$1@paganini.bofh.team>
In reply to#394655
David Brown <david.brown@hesbynett.no> wrote:
> On 22/10/2025 16:05, Janis Papanagnou wrote:
>> On 22.10.2025 15:41, David Brown 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?
>>>
>>> Presumably you meant "without any undefined behaviour" ?  The code is
>>> fine - if no cases match and there is no default case, execution
>>> continues from the end of the switch statement.  Like most warnings,
>>> this is about a possible bug in the code - not a definite one.
>>>
>>>>>
>>>>> 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.
>>>
>>> I don't think it is normally appropriate to add a default case unless
>>> you actually need it
>> 
>> Yes I was saying that I want it; I "need" it once errors slip in and
>> such a message or error log immediately clears the issue! (You might
>> be excluding some "needs" from your repertoire of necessities, okay.)
>> 
>>> - code that exists but can never be reached is
>>> untestable and can be confusing to people reading the code.  But
>>> sometimes it can be useful to add a "default : printf("Internal
>>> error...");" for debugging, however.
>> 
>> This printf error message or log entry is what I suggested. It isn't
>> confusing because it even _documents_ what's the case here. Rather,
>> a missing default leaves the reader with an unnecessary uncertainty.
>> YMMV.
>> 
> 
> Indeed YMMV.  But when I see a printf call that says something has gone 
> horribly wrong, I wonder /how/ that could happen.  I don't put such 
> statements into my code without it being a possible execution path.

IME it is a possible execution path unless you have very simple
and carefully checked proof that it is not.  I mean, you may
_think_ that you proved that given case can not happen, but
once your argument gets complex there is realistic chance of
error in your proof.  That happened to myself, but I had code
like:

    default:
       ERROR("Impossible");

and well, "Impossible" happened.

> I 
> agree, of course, that a good error message here makes the code somewhat 
> self-documenting in terms of what it does.  But it does nothing to help 
> say how it happened to run.  A printf call that never runs is not free - 
> it costs in many different ways, and should not be there unless it is 
> worth those costs.

That depends.  I one constext that means adding some tens of bytes
to binary, which is negligible given size to the thing of modern
PC-s.  Execution time usualy is negligible too (I do not have
switches in inner loops, so even if extra case leads to extra
comparison it does not matter much).  There is question of
consequences.  In my case unhandled case can easily lead to producing
wrong value, which is worst kind of error for the application.
Signaling error essentially means "can not do this" and is nothing
unusual.

In embedded context this is different, as you noted extra code
can exceed time budget.  Stopping device may not be an option
and there could be no way to print error message.  OTOH control
and date flow in embedded applications tend to be much simpler
than in PC applications, so chance of correct proof are better.

-- 
                              Waldek Hebisch

[toc] | [prev] | [next] | [standalone]


#394663

FromKeith Thompson <Keith.S.Thompson+u@gmail.com>
Date2025-10-22 12:41 -0700
Message-ID<87frbaohaa.fsf@example.invalid>
In reply to#394652
David Brown <david.brown@hesbynett.no> writes:
> 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?
>
> Presumably you meant "without any undefined behaviour" ?  The code is
> fine - if no cases match and there is no default case, execution
> continues from the end of the switch statement.  Like most warnings,
> this is about a possible bug in the code - not a definite one.

No, pozz meant "without any defined behavior", which is a direct quote
from the cited document.

That document is poorly written.  The phrase "without any defined
behavior" strongly implies that the behavior is undefined, which is
simply wrong.

It says:

    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.

It would be more accurate to say:

    When a switch statement lacks a default case, if a value is
    encountered that does not match any of the specified cases, the
    switch statement will do nothing and the program will continue
    execution without handling the value.

A warning might be warranted, but the behavior is well defined.

Note that the documentation is for the add-on tool clang-tidy, not for
the clang compiler.

I've submitted a bug report :

https://github.com/llvm/llvm-project/issues/164699

-- 
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */

[toc] | [prev] | [next] | [standalone]


#394672

Frompozz <pozzugno@gmail.com>
Date2025-10-23 08:47 +0200
Message-ID<10dcj1l$3t7o6$1@dont-email.me>
In reply to#394663
Il 22/10/2025 21:41, Keith Thompson ha scritto:
> David Brown <david.brown@hesbynett.no> writes:
>> 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?
>>
>> Presumably you meant "without any undefined behaviour" ?  The code is
>> fine - if no cases match and there is no default case, execution
>> continues from the end of the switch statement.  Like most warnings,
>> this is about a possible bug in the code - not a definite one.
> 
> No, pozz meant "without any defined behavior", which is a direct quote
> from the cited document.
> 
> That document is poorly written.  The phrase "without any defined
> behavior" strongly implies that the behavior is undefined, which is
> simply wrong.
> 
> It says:
> 
>      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.
> 
> It would be more accurate to say:
> 
>      When a switch statement lacks a default case, if a value is
>      encountered that does not match any of the specified cases, the
>      switch statement will do nothing and the program will continue
>      execution without handling the value.
> 
> A warning might be warranted, but the behavior is well defined.

It is exactly what i wanted to read. Thanks for the explanation.


> Note that the documentation is for the add-on tool clang-tidy, not for
> the clang compiler.

Sure


> I've submitted a bug report :
> 
> https://github.com/llvm/llvm-project/issues/164699
> 

[toc] | [prev] | [next] | [standalone]


#394693

FromKeith Thompson <Keith.S.Thompson+u@gmail.com>
Date2025-10-23 16:17 -0700
Message-ID<87frb92op0.fsf@example.invalid>
In reply to#394672
pozz <pozzugno@gmail.com> writes:
> Il 22/10/2025 21:41, Keith Thompson ha scritto:
[...]
>> That document is poorly written.  The phrase "without any defined
>> behavior" strongly implies that the behavior is undefined, which is
>> simply wrong.
>> It says:
>>      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.
>> It would be more accurate to say:
>>      When a switch statement lacks a default case, if a value is
>>      encountered that does not match any of the specified cases, the
>>      switch statement will do nothing and the program will continue
>>      execution without handling the value.
>> A warning might be warranted, but the behavior is well defined.
>
> It is exactly what i wanted to read. Thanks for the explanation.
>
>
>> Note that the documentation is for the add-on tool clang-tidy, not for
>> the clang compiler.
>
> Sure
>
>
>> I've submitted a bug report :
>> https://github.com/llvm/llvm-project/issues/164699

My fix for this has been accepted into the llvm-project git repo.

The web page
https://clang.llvm.org/extra/clang-tidy/checks/bugprone/switch-missing-default-case.html
has not yet been updated (not surprisingly).

commit b474be668091301d4a214da922f0cb98d416dc6b
Author: Keith Thompson <Keith.S.Thompson@gmail.com>
Date:   2025-10-23 02:41:12 -0700

    [clang-tidy][NFC] Clarify switch-missing-default-case doc (#164699) (#164709)
    
    Falling through a defaultless switch statement has well defined
    behavior. Fixes https://github.com/llvm/llvm-project/issues/164699.
    
    Credit for noticing this problem goes to user "pozz" on comp.lang.c,
    Message-ID: <10da67g$3q59f$1@dont-email.me>

diff --git clang-tools-extra/docs/clang-tidy/checks/bugprone/switch-missing-default-case.rst clang-tools-extra/docs/clang-tidy/checks/bugprone/switch-missing-default-case.rst
index 648c2c208a4e..3ce862ff8afc 100644
--- clang-tools-extra/docs/clang-tidy/checks/bugprone/switch-missing-default-case.rst
+++ clang-tools-extra/docs/clang-tidy/checks/bugprone/switch-missing-default-case.rst
@@ -9,8 +9,8 @@ on covering cases with non-enums where the compiler may not issue warnings.
 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.
+specified cases, the switch statement will do nothing and the program will
+continue execution without handling the value.
 
 This check helps identify switch statements that are missing a default case,
 allowing developers to ensure that all possible cases are handled properly.

-- 
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */

[toc] | [prev] | [next] | [standalone]


#394699

FromKeith Thompson <Keith.S.Thompson+u@gmail.com>
Date2025-10-23 19:13 -0700
Message-ID<87y0p111ys.fsf@example.invalid>
In reply to#394693
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
> pozz <pozzugno@gmail.com> writes:
>> Il 22/10/2025 21:41, Keith Thompson ha scritto:
> [...]
>>> That document is poorly written.  The phrase "without any defined
>>> behavior" strongly implies that the behavior is undefined, which is
>>> simply wrong.
>>> It says:
>>>      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.
>>> It would be more accurate to say:
>>>      When a switch statement lacks a default case, if a value is
>>>      encountered that does not match any of the specified cases, the
>>>      switch statement will do nothing and the program will continue
>>>      execution without handling the value.
>>> A warning might be warranted, but the behavior is well defined.
>>
>> It is exactly what i wanted to read. Thanks for the explanation.
>>
>>> Note that the documentation is for the add-on tool clang-tidy, not for
>>> the clang compiler.
>>
>> Sure
>>
>>
>>> I've submitted a bug report :
>>> https://github.com/llvm/llvm-project/issues/164699
>
> My fix for this has been accepted into the llvm-project git repo.
>
> The web page
> https://clang.llvm.org/extra/clang-tidy/checks/bugprone/switch-missing-default-case.html
> has not yet been updated (not surprisingly).

And now it's been updated:

    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 switch
    statement will do nothing and the program will continue execution
    without handling the value.

-- 
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */

[toc] | [prev] | [next] | [standalone]


#394676

FromDavid Brown <david.brown@hesbynett.no>
Date2025-10-23 10:44 +0200
Message-ID<10dcptu$1gk7g$1@dont-email.me>
In reply to#394663
On 22/10/2025 21:41, Keith Thompson wrote:
> David Brown <david.brown@hesbynett.no> writes:
>> 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?
>>
>> Presumably you meant "without any undefined behaviour" ?  The code is
>> fine - if no cases match and there is no default case, execution
>> continues from the end of the switch statement.  Like most warnings,
>> this is about a possible bug in the code - not a definite one.
> 
> No, pozz meant "without any defined behavior", which is a direct quote
> from the cited document.
> 

OK.

> That document is poorly written.  The phrase "without any defined
> behavior" strongly implies that the behavior is undefined, which is
> simply wrong.

I guess I owe Pozz an apology for thinking he had made a little typo, 
when in fact it was a clear error from the clang-tidy folk!  Thanks for 
clearing that up.

> 
> It says:
> 
>      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.
> 
> It would be more accurate to say:
> 
>      When a switch statement lacks a default case, if a value is
>      encountered that does not match any of the specified cases, the
>      switch statement will do nothing and the program will continue
>      execution without handling the value.
> 
> A warning might be warranted, but the behavior is well defined.
> 
> Note that the documentation is for the add-on tool clang-tidy, not for
> the clang compiler.
> 
> I've submitted a bug report :
> 
> https://github.com/llvm/llvm-project/issues/164699
> 

It looks like your patch has been accepted, as far as I could tell. 
Very helpful!


[toc] | [prev] | [next] | [standalone]


#394653

FromJanis Papanagnou <janis_papanagnou+ng@hotmail.com>
Date2025-10-22 15:56 +0200
Message-ID<10danqv$ltmu$1@dont-email.me>
In reply to#394649
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.

Janis

> 
> $ cat x.c
> #include <stdio.h>
> 
> enum x {A, B, C};
> 
> int main(void)
> {
>     enum x x = C;
> 
>     switch (x)
>     {
>         case A:
>             printf("A\n");
>             break;
> 
>         case B:
>             printf("B\n");
>             break;
>     }
> 
>     return 0;
> }
> 
> $ gcc -Wall x.c
> x.c: In function ‘main’:
> x.c:9:9: warning: enumeration value ‘C’ not handled in switch [-Wswitch]
>     9 |         switch (x)
>       |         ^~~~~~
> 
> 
> 

[toc] | [prev] | [next] | [standalone]


#394656

FromDavid Brown <david.brown@hesbynett.no>
Date2025-10-22 17:25 +0200
Message-ID<10dat1m$nfjr$2@dont-email.me>
In reply to#394653
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.  If that part doesn't exist (since it is 
"optional"), then the default line is not "taking precautions", it is 
normal handling of a realistic situation.

[toc] | [prev] | [next] | [standalone]


#394669

FromJanis Papanagnou <janis_papanagnou+ng@hotmail.com>
Date2025-10-23 04:39 +0200
Message-ID<10dc4gn$15ir6$1@dont-email.me>
In reply to#394656
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.

Janis

[toc] | [prev] | [next] | [standalone]


#394673

FromDavid Brown <david.brown@hesbynett.no>
Date2025-10-23 09:08 +0200
Message-ID<10dck93$1dnn6$1@dont-email.me>
In reply to#394669
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).





[toc] | [prev] | [next] | [standalone]


#394696

FromKeith Thompson <Keith.S.Thompson+u@gmail.com>
Date2025-10-23 16:31 -0700
Message-ID<877bwl2o0h.fsf@example.invalid>
In reply to#394656
David Brown <david.brown@hesbynett.no> writes:
> On 22/10/2025 15:56, Janis Papanagnou wrote:
[...]
>>    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.  If that part doesn't exist (since
> it is "optional"), then the default line is not "taking precautions",
> it is normal handling of a realistic situation.

Error handling can be complicated.

You're right that code that prints a message for a condition that
should never happen (equivalently, that can only happen as a result
of a programming error) is difficult to test.  (I suppose you could
tweak the code to introduce an error so the message is triggered,
but that's ugly and difficult to automate.)

For example, the failure of the first Ariane 5 launch involved
an unexpected error diagnostic message being interpreted as data.
If the error had been quietly ignored, the rocket might have survived.

If a condition is really expected never to happen, something
like gcc's _builtin_unreachable might be useful, or more portably
an assert.

If you want to test for a condition that should never happen, you
need to think about how you would want to handle it.  If the best
way to handle it is to abort the application, that's easy enough.
If it's a safety critical system, though, it might be better to
attempt to log an error message (in a way that won't itself cause
a problem) and try to continue running.

And yes, handling a condition that can actually happen (say, in the
presence of bad input) is quite different.

-- 
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */

[toc] | [prev] | [next] | [standalone]


#394704

FromDavid Brown <david.brown@hesbynett.no>
Date2025-10-24 10:09 +0200
Message-ID<10dfc82$2eobo$1@dont-email.me>
In reply to#394696
On 24/10/2025 01:31, Keith Thompson wrote:
> David Brown <david.brown@hesbynett.no> writes:
>> On 22/10/2025 15:56, Janis Papanagnou wrote:
> [...]
>>>     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.  If that part doesn't exist (since
>> it is "optional"), then the default line is not "taking precautions",
>> it is normal handling of a realistic situation.
> 
> Error handling can be complicated.
> 

That's a good entry for the "understatement of the week" competition!

> You're right that code that prints a message for a condition that
> should never happen (equivalently, that can only happen as a result
> of a programming error) is difficult to test.  (I suppose you could
> tweak the code to introduce an error so the message is triggered,
> but that's ugly and difficult to automate.)
> 
> For example, the failure of the first Ariane 5 launch involved
> an unexpected error diagnostic message being interpreted as data.
> If the error had been quietly ignored, the rocket might have survived.
> 
> If a condition is really expected never to happen, something
> like gcc's _builtin_unreachable might be useful, or more portably
> an assert.
> 

I like a macro that can then expand to different things according to 
what I want to do such as "__builtin_unreachable()" for gcc, 
"unreachable()" for C23, blank for other tools, for use with well 
checked and well tested code.  Alternatively it can expand to a check of 
some sort, a log, a debug message, an LED indicator, or whatever during 
testing, debugging, or fault-finding.

> If you want to test for a condition that should never happen, you
> need to think about how you would want to handle it.  If the best
> way to handle it is to abort the application, that's easy enough.
> If it's a safety critical system, though, it might be better to
> attempt to log an error message (in a way that won't itself cause
> a problem) and try to continue running.
> 

Indeed.  Very often you see error handling that is done without due 
thought about how the errors could occur, and what you should do about 
them.  I see code that obsessively checks "malloc" for zero returns, 
because someone heard that you should always check the result of 
"malloc".  That's fair enough if you are in a situation where malloc 
could fail, and when you can do something about it that is better than 
ignoring it - but usually malloc cannot fail in any remotely realistic 
use-case, and usually there's nothing you can do anyway that is better 
than continuing until dereferencing a null pointer crashes your code.

Basically, there's no point in asking a question until you have a plan 
of what to do with the answer.

> And yes, handling a condition that can actually happen (say, in the
> presence of bad input) is quite different.
> 

Very much so, yes.  "Edge" code - whether it is getting data from 
outside, or is an API called by external code - has to sanitize its 
inputs.  Internal code should not be second-guessing other parts of the 
same code - if you can't trust the different bits of the same project to 
get things right, you have big problems that can't be solved by adding 
default cases.  (Where the boundaries between "internal" and "edge" code 
go will obviously vary.)

[toc] | [prev] | [next] | [standalone]


#394660

FromKaz Kylheku <643-408-1753@kylheku.com>
Date2025-10-22 18:13 +0000
Message-ID<20251022101143.383@kylheku.com>
In reply to#394647
On 2025-10-22, pozz <pozzugno@gmail.com> wrote:
>
>  From here[1]:
>
>> 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.

It is just slop written by someone who is new to the subject matter.

"defined behavior" is a radioactive term that you simply don't
use so carelessly, when documenting a C implementation.

-- 
TXR Programming Language: http://nongnu.org/txr
Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
Mastodon: @Kazinator@mstdn.ca

[toc] | [prev] | [standalone]


Page 2 of 2 — ← Prev page 1 [2]

Back to top | Article view | comp.lang.c


csiph-web