home bbs files messages ]

Forums before death by AOL, social media and spammers... "We can't have nice things"

   comp.lang.c      Meh, in C you gotta define EVERYTHING      243,242 messages   

[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]

   Message 241,429 of 243,242   
   Thiago Adams to David Brown   
   Re: bugprone-switch-missing-default-case   
   23 Oct 25 13:15:30   
   
   From: thiago.adams@gmail.com   
      
   On 10/23/2025 12:06 PM, David Brown wrote:   
   > On 23/10/2025 13:03, Thiago Adams wrote:   
   >> 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  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    
   >>>>>>   
   >>>>>> 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.   
   >>   
   >>   
   >   
   > As I said - use "-Wswitch=error".  That gives you a compile-time error -   
   > not merely a warning, as you had suggested.  But /if/ your switch is not   
   > meant to handle all cases, which was what Kaz was complaining about,   
   > then you add a default case.  I agree with you that a compile-time error   
   > is best when possible, which is why that was my suggestion.   
   >   
   >   
   >   
      
      
   I think my sample is not covered by any GCC flag   
      
      
   I will copy past it again:   
   --------   
   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.   
      
   --------   
      
   --- SoupGate-Win32 v1.05   
    * Origin: you cannot sedate... all the things you hate (1:229/2)   

[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]


(c) 1994,  bbs@darkrealms.ca