I found this line in my work project, but I can't understand this:
extern const volatile uint8 * const volatile array[];
Could you please help me explain the line?
First, leaving out the qualifiers:
uint8 *array[];
array
is an array of unspecified size whose elements are of type uint8 *
. In other words, an array of pointers to uint8
.
If this declaration appears as a parameter to a function, the array syntax is actually shorthand for a pointer. If it is not a function parameter and is declared at file scope then this acts as a tentative definition. A complete definition may occur elsewhere in the code that specifies the size and optionally an initializer. If no other complete definition exists, then the array is defined to have 1 element.
Before talking about what the declaration means with the qualifiers, let's first talk about exactly what those qualifiers mean.
The const
qualifier prevents code from modifying the named object. Given this declaration:
const int x;
It means that x
can't be modified using for example x = 1
. With pointers involved it's a little more tricky:
const int *x;
This defines x
as a pointer to a const int
. That means that you can modify x
but not what it points to. So x = &y
is legal but not *x = 1
.
int * const x;
This defines x
as a const
pointer to an int
, which means you can't modify x
but you can modify what it points to. So x = &y
is not legal but *x = 1
is.
const int * const x;
This defines x
as a const
pointer to a const int
. So in this case, neither x
nor what it points to can be modified.
const int * const x[];
Here, x
is an array whose elements are const
pointers to a const int
. As in the prior example, for each array element, neither the array element nor what it points to can be modified.
Now let's talk about volatile
. This qualifier tells the compiler that the variable in question might change unpredictably. From section 6.7.3p7 of the C standard:
An object that has volatile-qualified type may be modified in ways unknown to the implementation or have other unknown side effects. Therefore any expression referring to such an object shall be evaluated strictly according to the rules of the abstract machine, as described in 5.1.2.3. Furthermore, at every sequence point the value last stored in the object shall agree with that prescribed by the abstract machine, except as modified by the unknown factors mentioned previously. 134) What constitutes an access to an object that has volatile-qualified type is implementation-defined
134) A
volatile
declaration may be used to describe an object corresponding to a memory-mapped input/output port or an object accessed by an asynchronously interrupting function. Actions on objects so declared shall not be "optimized out" by an implementation or reordered except as permitted by the rules for evaluating expressions
What this means is that a volatile
object could change in ways not known to the compiler, and thus the compiler should not perform any optimizations on this variable and in fact should assume the value was changed externally.
Now moving on the your full declaration:
const volatile uint8 * const volatile array[];
This declares array
as an array of unspecified size whose elements are of type uint8 *
, where the elements of the array cannot be modified by the program (i.e. are const
) but could be modified externally (i.e. volatile
), and what those array elements point to also cannot be changed by the program but could be modified externally.