Static and volatile qualifiers after type

Bjarne explains why const can come before or after a type.

http://www.stroustrup.com/bs_faq2.html#constplacement

"const T" and "T const" were - and are - (both) allowed and equivalent.
[...]

      

Why? When I invented "const" (originally called "readonly" and had a corresponding "writeonly"), I allowed it to go before or after because I could do it without ambiguity.

My immediate thought was, "Okay, that makes sense, but if that's the reason, then why is const special?" Apparently this is not the case. Both clang and gcc do not issue any warnings about the following.

int volatile myint;
int static myotherint;

      

It makes sense that it would be valid, but I've never seen this syntax used or even mentioned as a possibility. Puts static and volatile qualifiers after a valid C ++ type?

How to determine this from the text of the standard?

+3


source to share


3 answers


These parts are actually quite broadly separated in the standard. static

- storage class as specified in clause 7.1.1 / 1:

storage-class-specifier:
    register
    static
    thread_local
    extern
    mutable

      

This is used in the decl specifier as defined in 1.7:



decl-specifier:
    storage-class-specifier
    type-specifier
    function-specifier
    friend
    typedef
    constexpr

decl-specifier-seq:
    decl-specifier attribute-specifier-seqopt
    decl-specifier decl-specifier-seq

      

So it allows you to either static int

or int static

specify the type. Likewise, you can declare a friend function as friend int f();

or int friend f();

.

const

or volatile

can only participate if you actually declare something, so it falls under "declarators" in § 8. This part of the grammar is long enough, I'm too lazy to format it all, but it points the init-declarator list to top level, then the declarator and (skipping multiple levels) is reset to cv-qualifier

which is either const

or volatile

. At least from my reading, it basically allows const

or is volatile

free to mix with other things that type indicates.

+2


source


Yes, this syntax is fine. The first part of the grammar of the declaration is a sequence of decl specifiers. These include settings for storage class specifiers types, functions friend

, typedef

and constexpr

. The grammar allows them to appear in any order. However, the semantic rules introduced on them introduce some restrictions. For example, a variable declaration must always have one type specifier that is not a cv qualifier ( const

or volatile

). Also, there must not be more than one storage class specifier (except thread_local

may appear with static

or extern

).

Note that the sequence of declaration specifiers appears before any composite type syntax, such as pointers, references, arrays, etc. For example, the decl specifier sequence is noted in the following examples:

static const int *p;
|              |

char volatile static *(&p)[20];
|                  |

      



Note that volatile

is a cv classifier like const

, so the reasons to allow volatile

in the example you give are the same as for const

. These keywords can also appear deeper in the declaration (as in int *volatile x;

).

By convention, we write the storage class first, then follow the type hints and cv qualifiers where appropriate. I prefer to write my CV qualifications after the type specifiers they correspond to as they are more consistent.

You might want to read What are declarations and declarators and how are their types interpreted by the standard? ...

+4


source


Well, that's what I think. I am trying to interpret this.

static int *ptr1;
int* static ptr2;

      

the former means that it is a pointer pointing to a static integer. the second means that it is a static variable with an integer pointer type.

I think the other way should have a similar intuition.

0


source







All Articles