如何在类型定义上为结构成员分配预定义值?

时间:2017-04-13 13:45:33

标签: c struct types initialization c99

这是一个很长的镜头,但也许会有一些想法。在我编程的系统上,我已经定义了编程处理器寄存器的结构。这些寄存器由几个字段组成,每个字段有几个字位,可能是"保留"介于两者之间。写入寄存器时,保留位必须写为零。

例如:

reserved

我希望能够将List<MyCalculationOject> calculationOjects = dt.AsEnumerable().Select( row => new MyCalculationOject { Figure1 = row.Field<double>("figure1_Col"), Figure2 = row.Field<double>("figure2_Col"), ....})).ToList(); public class MyCalculationOject { public double Figure1 {get;set;} ... public double SomeBasicCalculation() {..} } 字段设置为默认值(在此示例中为0),并且无需显式分配(在我们的系统中会发生很多事情)。

请注意,如果实例化的对象是静态的,那么默认情况下,未初始化的字段将为0.但是,在上面的示例中没有保证,我还需要设置任意值。

2 个答案:

答案 0 :(得分:2)

C中的结构类型定义不能表示结构成员的值。它没有机制。结构实例定义可以。

  

我希望能够将保留字段设置为默认值(0 in   这个例子),并且不需要明确的分配(这个   在我们的系统中发生了很多事情。)

     

注意,如果实例化的对象是静态的,那么默认情况下是   未初始化的字段将为0.但是,在上面的例子中有   不保证,我也需要设置任意值。

你想要的默认值是0是偶然的。但是你似乎有一个误解:你不能部分初始化一个C对象。如果在结构对象的声明中提供初始化程序,那么未显式初始化的任何成员将获得与对象具有静态存储持续时间且没有初始化程序时相同的值。

因此,您可以这样做:

void set_ctrl() {
    ctrl_t r = {
        .power    = 1,
        .speed    = 22,
        // not needed:
        // .reserved = 0
    };

    // ...

如果你想要一个简单的方法用一组默认值初始化整个结构,有些非零,那么你可以考虑为初始化器写一个宏:

#define CTRL_INITIALIZER { .power = 1, .speed = 22 }

// ...

void set_other_ctrl() {
    ctrl_t r = CTRL_INITIALIZER;
    // ...

同样,您可以为初始化程序的部分内容定义宏:

#define CTRL_DEFAULTS .power = 1 /* no .speed = 22 */

// ...

void set_other_ctrl() {
    ctrl_t r = { CTRL_DEFAULTS, .speed = 22 };
    // ...

在这种情况下,您甚至可以覆盖默认值:

    ctrl_t r = { CTRL_DEFAULTS, .power = 2, .speed = 22 };

...但重要的是要记住只使用指定的成员初始值设定项,如上所述,而不是未指定的值。

答案 1 :(得分:1)

无法完成。

C语言中没有C ++意义上的“构造函数”。无论何时创建某个类型的值都无法保证任意代码运行,因此无法完成。事实上,在C中,“创造”价值是一个相当失落的概念。

考虑一下:

char buf[sizeof (ctrl_t)];
ctrl_t * const my_ctrl = (ctrl_t *) buf;

在此代码中,指针赋值还必须包含将buf的位设置为各种默认值的代码,以使其按您希望的方式工作。

在C中,“你所看到的就是你得到的”经常成立,生成的代码通常是可预测的,或者由于优化而更好。但是那种“神奇”的副作用实际上并不是C的运作方式。

最好不要暴露“原始”寄存器,而是抽象出保留位的存在:

void set_ctrl(uint8_t power, uint8_t speed)
{
  const uint32_t reg = ((uint32_t) power << 29) | speed;
  *(uint32_t *) 0x12345678 = reg;
}

这以一种将未使用的位设置为0的方式显式计算reg。您当然可以添加断言以确保不超过3位和5位范围限制。