I have run into a weird code
static ROMCONST struct testcase * ROMCONST *patterns[] = {
patternbmk,
NULL
};
This code could be found here.
What kind of struct definition/declaration is this?
Could someone explain in plain English what does it mean?
Regarding
ROMCONST
:As far as we are concerned for understanding these declarations,
ROMCONST
is just some noise macro used in place ofconst
.Such defines are common in embedded systems where you sometimes need non-standard stuff in order to allocate data in flash. Harvard architectures in particular are notorious for this, but also 8/16 bit MCUs that might need non-standard
*far
pointers. And finally in case the table is allocated in EEPROM/data flash, it can be updated in run-time despite being read-only, so then we'd want to addvolatile
. All of these things could be hidden insideROMCONST
. So we could in theory have something messy and partially non-standard like(Where
volatile
is from eeprom/data flash,const
for any kind of flash,far
for banked memory andPROGMEM
something used for declaring data in ROM on Harvard MCUs.)For now, I'll just ignore this and replace it with
const
.To understand the
const
-qualifiers of the rest of the code, start with the pointed-at arrays likepatternbmk
.Picking this apart:
struct testcase * patternbmk[]
declares an array of pointers to structs.const struct testcase * patternbmk[]
gives those pointers read-only access. The pointed-at data isconst
and can't be modified through these pointers.const struct testcase * const patternbmk[]
makes the pointers themselves read-only, which mainly serves the purpose of ensuring that the table is allocated in flash rather than RAM.It might be helpful to adapt a coding style such as
*const
, writing the pointer declaration and its qualifier together.Next up the programmer wished to declare an array of pointers to these pointer arrays. (As you can tell this is starting to get messy...) There are two ways that can be used to point at a pointer array, either by pointing at the array with an array pointer or by pointing at the first item of the array with a pointer-to-pointer. The programmer chose the latter.
The array item is of type
const struct testcase * const
and in order to point at such an item, we add an additional*
to the right, ending up withconst struct testcase * const *
. It is helpful to read messy declarations like this from right to left: pointer to const-pointer to const struct testcase.And then they wished to make an array of such pointer-to-pointers, simply add a
[]
to the end:const struct testcase * const *patterns[]
.Not that each initializer in this array implicitly "decays" into a pointer to the first item, so the intializer
patternbmk
decays into&patternmk[0]
which happens to be a pointer to const-pointer to const struct testcase, same type as I discussed above.And finally the
static
qualifier is just there to limit variable scope to the file where it is declared. NULL at the end of thepatterns
initializer list is a sentinel value, marking the end of the array.