From: david.brown@hesbynett.no   
      
   On 23/10/2025 18:15, Thiago Adams wrote:   
   > 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;   
   > };   
   >   
   > }   
   >   
   I appreciate that enumerations in C are missing a lot of potential   
   compared to enumerations in some other languages (they could be real new   
   types that do not implicitly convert with "int", they could have a   
   "count" feature, they could have a feature for having the identifier   
   names in a const array of strings, etc.). But none of this is at all   
   hard with today's enums :   
      
   enum E1 { A, B, C, D, last_E1 = D };   
      
    void f(enum E1 e)   
    {   
    switch (e)   
    {   
    //used   
    case A:   
    case B:   
    break;   
      
    default:   
    static_assert(last_E1 == D);   
    // or, according to preference   
    static_assert(last_E1 == 4);   
    break;   
    };   
      
    }   
      
   People do this regularly. Personally, I usually prefer to have the   
   "last", "max", or "count" indicator outside the enumeration :   
      
    enum E1 { A, B, C, D };   
    static const int count_of_E1 = D;   
      
   It is not standardised, so different people use different names, but   
   it's perfectly doable.   
      
   And if you want to automate it a little more and negate the possibility   
   of forgetting to change the "count_of_E1" line, because automation of   
   these things is nice, then I think you could easily put together an   
   XMacro style solution.   
      
      
   [continued in next message]   
      
   --- SoupGate-Win32 v1.05   
    * Origin: you cannot sedate... all the things you hate (1:229/2)   
|