Consider
volatile int volatile * volatile vip; // (1)
and
volatile int volatile * volatile vipa[10]; // (2)
Both lines of code trigger -Wduplicate-decl-specifier
(see rev 236142
and gcc7 release notes). I'd like to know if I can remove some volatile
specifiers from the given code without changing the semantics of the code, and understand the reasons behind it, too.
Thus, the following questions:
a. In (1), do the 1st and 2nd volatile
qualifiers both refer to int
, thus being "duplicate" in gcc terms? (I'm looking at C99 6.7.3.4 here.)
b. In (2), does one of the volatile
qualifiers refer to the type of the array, and not the int
or the pointer itself, so that C99 6.7.3.8 holds:
If the specification of an array type includes any type qualifiers, the element type is so-qualified, not the array type.
or do the volatile
specifiers in (2) only affect the int
and the pointer
type, and not the type of the array?
c. If the answer to b is negative, how do I declare a volatile
array type that is described in C99 6.7.3.8? Is it the syntax described at https://en.cppreference.com/w/c/language/array (quote follows)?
qualifiers - any combination of const, restrict, or volatile qualifiers, only allowed in function parameter lists; this qualifies the pointer type to which this array parameter is transformed
Let's consider this a question about C99. If there are any differences in C11 in this regard, please make a note.
TL;DR:
- In (1), do the 1st and 2nd
volatile
qualifiers both refer toint
, thus being "duplicate" in gcc terms? (I'm looking at C99 6.7.3.4 here.)
yes, they both qualify the int
and they're the duplicate.
- In (2), does one of the volatile qualifiers refer to the type of the array, and
not
the int or the pointer itself, so that C99 6.7.3.8 holds:
C99 6.7.3.8 does not hold here. The qualifier already applies to the element type. It is possible to apply a qualifier to an array with a typedef, but that also qualifies the element type (see below)
c. If the answer to b is negative, how do I declare a volatile array type that is described in C99 6.7.3.8?
With a typedef
for example.
The C standard explicitly allows qualifiers to occur more than once. C11 n1570 6.7.3p5:
If the same qualifier appears more than once in the same specifier-qualifier-list, either directly or via one or more typedefs, the behavior is the same as if it appeared only once.
i.e. what -Wduplicate-decl-specifier
is not an error as such, but such code verbatim is suspicious - should it be volatile int *volatile
that was misspelt as volatile int volatile *
causing the pointer to be unqualified...
The qualifiers apply to type of the left left of the qualifier, except if the qualifier itself is the leftmost one, in which case it is as if it was right of the base type i.e.
volatile int *
and
int volatile *
mean the same thing. Therefore in volatile int volatile
you can remove one of these. Thus the thing what you need is
volatile int *volatile vipa[10];
Meaning that vipais an array of 10
volatile-qualified pointers to
volatileint`s.
What the C99 6.7.3p8/C11 6.7.3p9 means is that an array as itself cannot be volatile - its address is constant, only its elements can be qualified. hence if an array type is qualified, it only applies to its elements. This is even so if a typedef is qualified:
typedef int intarray[5];
const intarray myarray;
will declare myarray
as if by
const int myarray[5];
whereas if you'd use typedef for a pointer:
typedef int *intptr;
const intptr myptr;
this qualifier would not affect the pointed-to type but be equivalent to
int *const myptr;
While both volatile int
and int volatile
are strictly allowed, the C standard prefers the former. C11 n1570 6.7.6.1p3:
EXAMPLE The following pair of declarations demonstrates the difference between a ''variable pointer to a constant value'' and a ''constant pointer to a variable value''.
const int *ptr_to_constant; int *const constant_ptr;
The contents of any object pointed to by
ptr_to_constant
shall not be modified through that pointer, butptr_to_constant
itself may be changed to point to another object. Similarly, the contents of theint
pointed to byconstant_ptr
may be modified, butconstant_ptr
itself shall always point to the same location.
It is further possible to add a type qualifier for an array within the brackets, but only in function parameters, so you can write
void foo(int array[volatile])
which means almost the same and the parameter decays to a qualified pointer
void foo(int *volatile array)
but you can use the static
specifier only with the former style.
the explanation is simple.
volatile int *
== int volatile *
in this case order does not matter.
So volatile int * volatile x;
== int volatile * volatile x;
if you have volatile int volatile *
you have already declared it as volatile do the second one is not needed
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With