Where in a declaration may a storage class specifier be placed?

前端 未结 3 754
天命终不由人
天命终不由人 2020-12-14 02:07

For example, let\'s consider the static storage class specifier. Here are a few examples of both valid and ill-formed uses of this storage class specifier:

3条回答
  •  小蘑菇
    小蘑菇 (楼主)
    2020-12-14 02:40

    If you employ the "Golden Rule" (which also doesn't apply only to pointers) it follows naturally, intuitively, and it avoids a lot of mistakes and pitfalls when declaring variables in C/C++. The "Golden Rule" should not be violated (there are rare exceptions, like const applied to array typedefs, which propagates const to the base type, and references, that came with C++).

    K&R, Appendix A, Section 8.4, Meaning of Declarators states:

    Each declarator is taken to be an assertion that when a construction of the same form as the declarator appears in an expression, it yields an object of the indicated type and storage class.

    To declare a variable in C/C++ you should really think of the expression you should apply to it to get the base type.

    1) There should be a variable name

    2) Then comes the expression as valid* out of the declaration statement, applied to the variable name

    3) Then comes the remaining information and properties of declaration like base type and storage

    Storage is not a characteristic you can always confer to the outcome of expressions, contrary to constness for example. It makes sense only at declaration. So storage must come somewhere else that's not in 2.

    int * const *pp;
    /*valid*/
    
    int * static *pp;
    /*invalid, this clearly shows how storage makes no sense for 2 and so breaks   */
    /*the golden rule.                                                             */
    /*It's not a piece of information that goes well in the middle of a expression.*/
    /*Neither it's a constraint the way const is, it just tells the storage of     */
    /*what's being declared.                                                       */
    

    I think K&R wanted us to use inverted reasoning when declaring variables, it's frequently not the common habit. When used, it avoids most of complex declaration mistakes and difficulties.

    *valid is not in a strict sense, as some variations occur, like x[], x[size, not indexing], constness, etc... So 2 is a expression that maps well (for the declaration usage), "same form", one that reflects variable's use, but not strictly.

    Golden Rule Bonus for the Uninitiated

    #include 
    
    int (&f())[3] {
        static int m[3] = {1, 2, 3};
        return m;
    }
    
    int main() {
        for(int i = 0; i < sizeof(f()) / sizeof(f()[0]); ++i)
            std::cout << f()[i] << std::endl;
    
        return 0;
    }
    

    In the context of declarations, & is not an operation to get an address, it just tells what's a reference.

    • f(): f is a function
    • &return: its return is a reference
    • reference[3]: the reference is to an array of 3 elements
    • int array[i]: an element is an int

    So you have a function that returns a reference to an array of 3 integers, and as we have the proper compile time information of the array size, we can check it with sizeof anytime =)

    Final golden tip, for anything that can be placed before the type, when in multiple declarations, it's to be applied to all the variables at once, and so can't be applied individually.

    This const can't be put before int:

    int * const p;
    

    So the following is valid:

    int * const p1, * const p2;
    

    This one can:

    int const *p; // or const int *p;
    

    So the following is invalid:

    int const *p1, const *p2;
    

    The exchangeable const is to be applied for all:

    int const *p1, *p2; // or const int *p1, *p2;
    

    Declaration Conventions

    Because of that, I always put everything that can't be put before the type, closer to the variable (int *a, int &b), and anything that can be put before, I put before (volatile int c).

    There's much more on this topic at http://nosubstance.me/post/constant-bikeshedding/.

提交回复
热议问题