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,401 of 243,242   
   Thiago Adams to Richard Harnden   
   Re: bugprone-switch-missing-default-case   
   22 Oct 25 10:05:58   
   
   From: thiago.adams@gmail.com   
      
   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.   
      
   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