• bugprone-switch-missing-default-case

    From pozz@pozzugno@gmail.com to comp.lang.c on Wed Oct 22 10:56:17 2025
    From Newsgroup: comp.lang.c


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





    [1] https://clang.llvm.org/extra/clang-tidy/checks/bugprone/switch-missing-default-case.html
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Janis Papanagnou@janis_papanagnou+ng@hotmail.com to comp.lang.c on Wed Oct 22 11:32:38 2025
    From Newsgroup: comp.lang.c

    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.

    Janis

    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Richard Harnden@richard.nospam@gmail.invalid to comp.lang.c on Wed Oct 22 12:44:45 2025
    From Newsgroup: comp.lang.c

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

    $ 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)
    | ^~~~~~



    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Thiago Adams@thiago.adams@gmail.com to comp.lang.c on Wed Oct 22 10:05:58 2025
    From Newsgroup: comp.lang.c

    On 10/22/2025 8:44 AM, Richard Harnden wrote:
    ....
    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 ...

    $ 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)
          |         ^~~~~~



    The problem with this GCC approach is when there are many enumerators
    but only a few are used.

    For instance :

    enum E {A, B, C, /*..., Z*/};

    1)
    void f(enum E e)
    {
    switch (e)
    {
    //used
    case A:
    case B:
    break;

    //NON USED
    case C:
    ...
    case Z:
    break;
    };
    }

    The problem with (1) is when we have too many
    non used enumerators, it is impractical to have a lot of switch cases.

    One alternative is to use default for all the non used:

    2)
    void f(enum E e)
    {
    switch (e)
    {
    //used
    case A:
    case B:
    break;

    //NON USED (all others)
    default:
    break;
    };
    }


    The problem with (2) is when we add a new enumerator and
    this new enumerations should be used, but there is no warning and it
    goes accidentally for default.


    Solution?

    In C2Y the new keyword _Countof was introduced.
    It works returns the number of elements of array. IT IS FOR ARRAY ONLY.

    I did an EXTENSION in my compiler where _Countof(enum E) also returns
    the number of enumerators.


    enum E2 {A, B};
    static_assert(_Countof(enum E2) == 2);

    (It also could be a new keyword.
    static_assert(_EnumCount(enum E2) == 2);)

    Having this we can do:

    3)
    void f(enum E e)
    {
    switch (e)
    {
    //used
    case A:
    case B:
    break;

    default:
    static_assert(_EnumCount(enum E2) == 20);
    break;
    };

    }

    Then when adding a new enumerator the programmer will have to review
    this code and update to 21 if it is not used, or handle it in a new case.

    This is also useful in other scenarios. For instance:


    enum E parse_enum_e(const char* s)
    {
    if (strcmp(s, "A") == 0) return A;
    if (strcmp(s, "B") == 0) return B;
    if (strcmp(s, "C") == 0) return C;
    if (strcmp(s, "D") == 0) return D;
    if (strcmp(s, "E") == 0) return E;
    if (strcmp(s, "F") == 0) return F;
    static_assert(_Countof(enum E) == 6);

    return A;
    }

    If a new enumerator is added we need to include it.

    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From David Brown@david.brown@hesbynett.no to comp.lang.c on Wed Oct 22 15:41:55 2025
    From Newsgroup: comp.lang.c

    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.


    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Janis Papanagnou@janis_papanagnou+ng@hotmail.com to comp.lang.c on Wed Oct 22 15:56:45 2025
    From Newsgroup: comp.lang.c

    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)
    | ^~~~~~




    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Janis Papanagnou@janis_papanagnou+ng@hotmail.com to comp.lang.c on Wed Oct 22 16:05:27 2025
    From Newsgroup: comp.lang.c

    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

    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From David Brown@david.brown@hesbynett.no to comp.lang.c on Wed Oct 22 17:23:04 2025
    From Newsgroup: comp.lang.c

    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.


    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From David Brown@david.brown@hesbynett.no to comp.lang.c on Wed Oct 22 17:25:42 2025
    From Newsgroup: comp.lang.c

    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.


    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Kaz Kylheku@643-408-1753@kylheku.com to comp.lang.c on Wed Oct 22 18:13:41 2025
    From Newsgroup: comp.lang.c

    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
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Kaz Kylheku@643-408-1753@kylheku.com to comp.lang.c on Wed Oct 22 18:22:50 2025
    From Newsgroup: comp.lang.c

    On 2025-10-22, Thiago Adams <thiago.adams@gmail.com> wrote:
    On 10/22/2025 8:44 AM, Richard Harnden wrote:
    ....
    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 ...

    $ 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)
          |         ^~~~~~



    The problem with this GCC approach is when there are many enumerators
    but only a few are used.

    The problem with the C and GCC approach is that there is no
    one-size-fits all solution.

    Some switches are intended to be exhaustive, such that
    missing a case is a bug.

    Some are not.

    You need an "eswitch" for the exhaustively handled enumerations, and
    switch for the others.

    GCC can turn on diagnostics over ranges of a file with pragma
    and there is also _Pragram, but it's all too clumsy.

    In Common Lisp we have case vs ecase:

    (case 3 (0 "zero") (1 "one") (2 "two"))
    NIL
    (case 0 (0 "zero") (1 "one") (2 "two"))
    "zero"
    (ecase 3 (0 "zero") (1 "one") (2 "two"))

    *** - The value of 3 must be one of 0, 1, 2
    The value is: 3

    If falling through without hitting a case would be wrong, you use ecase; problem solved.
    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Keith Thompson@Keith.S.Thompson+u@gmail.com to comp.lang.c on Wed Oct 22 12:41:49 2025
    From Newsgroup: comp.lang.c

    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 */
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Janis Papanagnou@janis_papanagnou+ng@hotmail.com to comp.lang.c on Thu Oct 23 04:39:17 2025
    From Newsgroup: comp.lang.c

    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

    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Janis Papanagnou@janis_papanagnou+ng@hotmail.com to comp.lang.c on Thu Oct 23 04:54:18 2025
    From Newsgroup: comp.lang.c

    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

    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From pozz@pozzugno@gmail.com to comp.lang.c on Thu Oct 23 08:47:16 2025
    From Newsgroup: comp.lang.c

    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


    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From David Brown@david.brown@hesbynett.no to comp.lang.c on Thu Oct 23 09:08:19 2025
    From Newsgroup: comp.lang.c

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






    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From David Brown@david.brown@hesbynett.no to comp.lang.c on Thu Oct 23 09:12:51 2025
    From Newsgroup: comp.lang.c

    On 22/10/2025 20:22, Kaz Kylheku wrote:
    On 2025-10-22, Thiago Adams <thiago.adams@gmail.com> wrote:
    On 10/22/2025 8:44 AM, Richard Harnden wrote:
    ....
    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 ...

    $ 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)
          |         ^~~~~~



    The problem with this GCC approach is when there are many enumerators
    but only a few are used.

    The problem with the C and GCC approach is that there is no
    one-size-fits all solution.

    Some switches are intended to be exhaustive, such that
    missing a case is a bug.

    Some are not.

    You need an "eswitch" for the exhaustively handled enumerations, and
    switch for the others.

    GCC can turn on diagnostics over ranges of a file with pragma
    and there is also _Pragram, but it's all too clumsy.


    The gcc approach works fine in almost all situations - use
    "-Wswitch=error", and add a default case if your switch is not meant to
    handle all enumeration values. If the default should do nothing, it's
    just "default: // Not all cases need handling". If the default should
    never happen, "default: __builtin_unreachable();" or "default: __builtin_trap();" might be appropriate.



    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From David Brown@david.brown@hesbynett.no to comp.lang.c on Thu Oct 23 09:30:46 2025
    From Newsgroup: comp.lang.c

    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.



    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From David Brown@david.brown@hesbynett.no to comp.lang.c on Thu Oct 23 10:44:46 2025
    From Newsgroup: comp.lang.c

    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!



    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Thiago Adams@thiago.adams@gmail.com to comp.lang.c on Thu Oct 23 08:03:00 2025
    From Newsgroup: comp.lang.c

    On 10/23/2025 4:12 AM, David Brown wrote:
    On 22/10/2025 20:22, Kaz Kylheku wrote:
    On 2025-10-22, Thiago Adams <thiago.adams@gmail.com> wrote:
    On 10/22/2025 8:44 AM, Richard Harnden wrote:
    ....
    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 ...

    $ 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)
            |         ^~~~~~



    The problem with this GCC approach is when there are many enumerators
    but only a few are used.

    The problem with the C and GCC approach is that there is no
    one-size-fits all solution.

    Some switches are intended to be exhaustive, such that
    missing a case is a bug.

    Some are not.

    You need an "eswitch" for the exhaustively handled enumerations,  and
    switch for the others.

    GCC can turn on diagnostics over ranges of a file with pragma
    and there is also _Pragram, but it's all too clumsy.


    The gcc approach works fine in almost all situations - use "- Wswitch=error", and add a default case if your switch is not meant to
    handle all enumeration values.  If the default should do nothing, it's
    just "default: // Not all cases need handling".  If the default should never happen, "default: __builtin_unreachable();" or "default: __builtin_trap();" might be appropriate.




    But then instead a compiler time error (like I suggest) you leave it for runtime.


    --- Synchronet 3.21a-Linux NewsLink 1.2