I want to declare a constant array of constant char arrays. If I write it like this:
const char foo[] = "Foo";
const char bar[] = "Bar";
const char* const foobar[2] = { foo, bar };
It seems to work, but if I try to read it using "the spiral rule", foobar is read as:
"foobar is an array 2 of constant (??) to a pointer to a char constant"
Using this stack overflow answer,
const applies to the thing left of it. If there is nothing on the left then it applies to the thing right of it.
the first const
would apply to the char, and the second const
would apply to same char as well.
Both ways of reading it doesn't make sense, but the code does function (in Arduino [sorry], at least). Which const
is making which a constant? Is there a more logical way to write it?
As you've stated:
const applies to the thing left of it. If there is nothing on the left then it applies to the thing right of it.
const char* const foobar[2] = { foo, bar };
can be re-written as:
char const * const foobar[2] = { foo, bar };
Now imagine the paratheses encapsulating const
qualifier and the entity qualified:
((char const) (* const)) foobar[2] = // doesn't matter
You've written that the second const would apply to same char as well. This is not true - the second const
refers to the *
, which means it's a constant pointer.
All in all, foobar
is an array of constant pointers to constant chars.
You may also want to read this thread: constant pointer vs pointer on a constant value .
A finicky but important point; in C it is not possible to have a const
array. (Ref: C11 6.3.2.3/2).
Everything that looks like it might be one is actually a non-const array whose elements are const
. Link to related discussion.
In your example const char* const foobar[2] = { foo, bar };
, the two const
keywords mean:
The text description is "foobar is an array 2 of constant pointer to a char constant".
Note the small but important distinction again that the chars being pointed to might actually be non-const char
, because a const char *
can point to both const and non-const. The effect of the first const
is to say that we might not know whether the chars are const or not, and so we can't safely write to them, so the compiler will generate an error if we try to use this pointer ot write to them.
foobar
is an array of const
pointers to const char
. An array is always constant, there is no way to explicitly make it const
.
In the declaration of function arguments, arrays decay to pointers, and a const
pointer does exist; in this case, const
can be put inside the []
. These are equivalent:
void func(int foo[const]) { ... }
void func(int *const foo) { ... }
The spiral rule isn't perfect (it fails for some complex declarations), and I personally don't find it helpful in combination with qualifiers (const
, volatile
etc). I don't know of anything rendering the rules exactly but the grammar itself (C11 6.7 and 6.7.6).
In this case, however, it seems to work:
+--------------+
| +---+ |
| ^ | |
const char *const foobar[2] |
^ ^ | |
| +----------+ |
+---------------------+
"foobar
is an array (with 2 elements) of const
pointers to const char
."
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