Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Forget the spiral rule. That's putting an if-statement into a buggy algorithm instead of using the correct algorithm.

The simplest correct algorithm is to 1. From the identifier, go right one by one in the current parenthesis level and process every element. 2. From the identifier again, go left one by one in the current parenthesis level and process every element. 3. Repeat from step 1. except the "identifier" is the part you already processed.

Within step 1, you will encounter arrays and function parameter lists. Within step 2, you will encounter pointers (in C++ also references), const and volatile modifiers, and named types. Neither algorithm covers it, but if there is no identifier to start with, then you start at the most nested level between the elements that may occur in step 1 and 2 and if you find a comma, you were just processing the type of a function parameter.

Spiraling is unnecessary. Within step 1, you DON'T spiral because of arrays of arrays or you turn back because of a closing parenthesis so a spiral doesn't need to guide you. Within step 2, the elements on the right are all processed already, so a spiral going back right will hit nothing. For simple but common cases like "const int * ptr * const_ptr_to_const_int" you're spiraling around nothing on the right-hand side.

Let's rework and simplify the examples from the http://c-faq.com/decl/spiral.anderson.html page. Comments show what the result of parsing an element is. Process >> >> left to right and << << right to left.

         char * str [10];
    //          XXX >>>> "str is", "an array of 10..."
    //   <<<< < XXX      "pointer to", "char"
    
         char * ( * fp ) ( int, float * );
    //              XX                    "fp is"
    //            < XX                    "a pointer to"
    //          XXXXXXXX >>>>>>>>>>>>>>>> "a function taking (int, float*) and returning"
    //   <<<< < XXXXXXXX                  "a pointer to", "char"
    
         void (* signal (int, void (* fp) (int))) (int);
    //                              < XX                "fp is", "a pointer to"
    //                             XXXXXX >>>>>         "a function taking (int) and returning"
    //                        <<<< XXXXXX               "void", "and it is a function parameter to something else"
    //           XXXXXX >>>>>>>>>>>>>>>>>>>>>>>>        "signal is", "a function taking (int, void(*fp)(int)) and returning"
    //         < XXXXXX                                 "a pointer to"
    //        XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX >>>>> "a function taking (int) and returning"
    //   <<<< XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX       "void"
    
         const char * chptr;
    //   <<<<< <<<< < XXXXX "chptr is", "a pointer to", "char", "that is const"
    // Notice how a spiral would make this worse and the page omits drawing it for a reason
    
         char * const chptr;
    //   <<<< < <<<<< XXXXX "chptr is", "a constant", "pointer to", "char"

         volatile char * const chptr;
    //   <<<<<<<< <<<< < <<<<< XXXXX "chptr is", "a constant", "pointer to", "char", "that is volatile"
Notice that in the examples where Anderson drew any spirals, it only made sense because there was a single "<<"/">>" element to the left and to the right of the XXXX part. In all other cases, spirals don't make sense because you might have to avoid the element on the left or there is no element on the right to spiral through, you're just going right-to-left. Why fit a spiral when a straight-line arrow will do?


Consider applying for YC's Winter 2026 batch! Applications are open till Nov 10

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: