列出const和数组结构字段的初始化

Ale*_*eon 3 c++ gcc c++11

刚开始使用微控制器进行C ++编程,我遇到了以下情况*:在始终保证具有固定值的结构上具有非静态const字段会很方便(对于每个实例,相同坚固)。

给定一个结构

struct S {
    const uint8_t c; // Should always be 42
    char v;
    uint32_t arr[4];
}
Run Code Online (Sandbox Code Playgroud)

我想c成为一个常数,每次都保持不变。我希望能够使用括号初始化程序列表的便利性来设置v和arr的成员,例如

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

由于我想c成为一个常数,因此,我的印象是,必须使用初始化列表进行设置c,例如S() : c(42) {},只要我不尝试也进行初始化arr,就可以正常工作。我迷失了清单的外观。使用C ++ 11可以做到吗?(如果这在C ++ 11中不可行,但在某些较新的标准中,也对答案很感兴趣。)

示例代码:

#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;
}
Run Code Online (Sandbox Code Playgroud)

*有关为什么要执行此操作的上下文:这看起来似乎很奇怪,因为如果值始终相同,为什么还要麻烦存储它呢?很好地想象,所讨论的结构是一个位域,对应于微控制器与之通信的IC的寄存器。这些寄存器有时具有“保留”字段,并且数据表指定必须在这些字段中写入的值。从程序员的角度来看,如果我不必手动处理这些位,那将很方便。

Nat*_*ica 6

C ++ 11为您提供std::array了一个原始数组,但没有任何“负数”(数组衰减,无法复制)。使用它,您可以获得想要的东西

struct S {
    const uint8_t c = 42;
    char v = 'a';
    std::array<uint32_t, 4> arr{};

    // This allows using "S s1;"
    S() {}

    S(uint32_t v, std::array<uint32_t, 4> arr) : v(v), arr{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

    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;
}
Run Code Online (Sandbox Code Playgroud)

哪个输出

s1.c = 42
s1.v = 'a'
s1.arr[3] = 0
s2.c = 42
s2.v = 'v'
s2.arr[3] = 3
Run Code Online (Sandbox Code Playgroud)

如果绝对要在其中包含原始数组,S则另一种选择是std::initializer_list在构造函数中使用a 。看起来像

struct S {
    const uint8_t c = 42;
    char v = 'a';
    uint32_t arr[4]{};

    // This allows using "S s1;"
    S() {}

    S(uint32_t v, std::initializer_list<uint32_t> data) : v(v)
    {
        int i = 0;
        for (auto e : data)
            arr[i++] = e;
    }
};

// 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

    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;
}
Run Code Online (Sandbox Code Playgroud)

而且,您获得的结果与使用的代码相同std::array