Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are both of these volatile qualifier usages redundant?

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.

like image 526
iksemyonov Avatar asked Mar 04 '23 02:03

iksemyonov


2 Answers

TL;DR:

  • 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.)

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 10volatile-qualified pointers tovolatileint`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:

  1. 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, but ptr_to_constant itself may be changed to point to another object. Similarly, the contents of the int pointed to by constant_ptr may be modified, but constant_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.

like image 112

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

like image 33
0___________ Avatar answered Mar 13 '23 07:03

0___________