vendredi 18 octobre 2019

List initialization of const and array structure fields

Just recently started C++ programming for micro-controllers, and I've ran into situations* where it would be convenient to have a const field on a struct that is always guaranteed to have a fixed value (same for every instance of the sturct, ever).

Given a struct

struct S {
    const uint8_t c; // Should always be 42
    char v;
    uint32_t arr[4];
}

I'd like c to be a constant value, and the same constant value every time. I would love to be able to use the convenience of brace initializer lists, for setting v and the members of arr like

S some_var = {'v', { 0, 1, 2, 3 } };

Since I'd like c to be a constant, I'm under the impression that I have to use an initializer list for setting c, such as S() : c(42) {}, which works just fine, as long as I don't try to also initialize arr, in which case I'm lost on how the list should look like. Is this doable using C++11? (Also interested in an answer if this is not doable in C++11, but in some newer standard.)

Example code:

#include <stdio.h>
#include <stdint.h>

struct S {
    const uint8_t c; // Should always be 42 on every instance
                     // of the struct due to hardware shenanigance
                     // (i.e. this struct is the representation of a register value)
    char v;
    uint32_t arr[4];

    // This allows using "S s1;"
    S() : c(42), v('a'), arr{} {}

    // This allows using "S s2 = { 'v', 0, 1, 2, 3 };" works but it's clumsy:
    S(uint32_t v, uint32_t arr0, uint32_t arr1, uint32_t arr2, uint32_t arr3) :
        c(42), v(v), arr{ arr0, arr1, arr2, arr3 } {}

    // I would like to do something along the lines of "S s2 = { 'v', { 0, 1, 2, 3 } };":
    // S(uint32_t v, uint32_t arr[4] /*?*/) :
    //     c(42), v(v), arr{/*?*/} {}

};

// Main just for the sake of completeness
int main() {
    // Works just fine
    S s1;
    printf("s1.c = %u\n", s1.c); // 42
    printf("s1.v = '%c'\n", s1.v); // a
    printf("s1.arr[3] = %u\n", s1.arr[3]); // 0

    // Initialiation like this works with the line:12 signature:
    S s2 = { 'v', 0, 1, 2, 3 };

    // I'd like to initialize like this:
    // S s2 = { 'v', { 0, 1, 2, 3 } };

    printf("s2.c = %u\n", s2.c); // 42
    printf("s2.v = '%c'\n", s2.v); // v
    printf("s2.arr[3] = %u\n", s2.arr[3]); // 3
    return 0;
}

*Context on why I'd want to do this: This might seem like a weird thing to want, since if the value is always the same, why bother storing it? Well imagine that the struct in question is a bitfield which corresponds to the register of an IC with which the micro-controller communicates. These registers sometimes have "reserved" fields, and the datasheet specifies what value you must write into these fields. From a programmer's point of view, it would be convenient if I never had to deal with setting said bits manually.

Aucun commentaire:

Enregistrer un commentaire