简体   繁体   English

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

[英]How to assign a predefined value to a struct member on type definition?

This is a long shot, but maybe there will be some ideas. 这是一个远景,但也许会有一些想法。 On a system I programming, I have defined structures to program processor registers. 在我编程的系统上,我定义了对处理器寄存器进行编程的结构。 The registers are comprised of several fields of a few bits each, with potentially "reserved" bits in between. 寄存器由几个字段组成,每个字段各占几位,并且它们之间可能有“保留”位。 When writing to a register, the reserved bits must be written as zeros. 写入寄存器时,保留位必须写为零。

For example: 例如:

typedef struct {
    uint32_t power    : 3;
    uint32_t reserved : 24;
    uint32_t speed    : 5;
} ctrl_t;

void set_ctrl()
{
    ctrl_t r = {
        .power    = 1;
        .speed    = 22;
        .reserved = 0;
    }

    uint32_t *addr = 0x12345678;

    *addr = *((uint32_t *) &r);

    return;
}

I want to be able to set the reserved field to a default value (0 in this example), and to spare the need for an explicit assignment (which happens a lot in our system). 我希望能够将reserved字段设置为默认值(在本示例中为0),并且无需进行显式分配(这在我们的系统中经常发生)。

Note that if the instantiated object is static, then by default an uninitialized field will be 0. However, in the above example there is no guarantee, and also I need to set any arbitrary value. 请注意,如果实例化的对象是静态的,则默认情况下,未初始化的字段将为0。但是,在上面的示例中,不能保证,并且我还需要设置任意值。

Structure type definitions in C cannot express values for structure members. C中的结构类型定义无法表达结构成员的值。 There is no mechanism for it. 没有任何机制。 Structure instance definitions can do. 结构实例定义可以做到。

I want to be able to set the reserved field to a default value (0 in this example), and to spare the need for an explicit assignment (which happens a lot in our system). 我希望能够将保留字段设置为默认值(在本示例中为0),并且无需进行显式分配(这在我们的系统中经常发生)。

Note that if the instantiated object is static, then by default an uninitialized field will be 0. However, in the above example there is no guarantee, and also I need to set any arbitrary value. 请注意,如果实例化的对象是静态的,则默认情况下,未初始化的字段将为0。但是,在上面的示例中,不能保证,并且我还需要设置任意值。

That the default value you want is 0 is fortuitous. 您想要的默认值为0是偶然的。 You seem to have a misunderstanding, though: you cannot partially initialize a C object. 但是,您似乎有一个误解:您无法部分初始化C对象。 If you provide an initializer in your declaration of a structure object, then any members not explicitly initialized get the same value that they would do if the object had static storage duration and no initializer. 如果在结构对象的声明中提供了初始值设定项,则任何未显式初始化的成员将获得与对象具有静态存储持续时间且没有初始值设定项时相同的值。

Thus, you can do this: 因此,您可以执行以下操作:

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

    // ...

If you want an easy way to initialize the whole structure with a set of default values, some non-zero, then you could consider writing a macro for the initializer: 如果您想要一种简单的方法来使用一组默认值(一些非零值)初始化整个结构,则可以考虑为初始化程序编写宏:

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

// ...

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

Similarly, you can define a macro for partial content of an initializer: 同样,您可以为初始化程序的部分内容定义一个宏:

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

// ...

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

In this case you can even override the defaults: 在这种情况下,您甚至可以覆盖默认值:

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

... but it is important to remember to use only designated member initializers, as above, not undesignated values. ...,但重要的是要记住仅使用如上所述的指定成员初始化器,而不要使用未指定的值。

It can't be done. 不能做

Values don't have "constructors" in the C++ sense in C. There's no way to guarantee that arbitrary code is run whenever a value of a certain type is created, so this can't be done. 在C中,值在C ++的意义上没有“构造函数”。无法确保每当创建某种类型的值时都运行任意代码,因此无法做到。 In fact "creation" of a value is quite a lose concept in C. 实际上,在C语言中,“创造”价值是一个必不可少的概念。

Consider this: 考虑一下:

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

In this code, the pointer assignment would have to also include code to set bits of buf to various defaults, in order for it to work like you want. 在此代码中,指针分配还必须包含将buf位设置为各种默认值的代码,以便它可以按您希望的方式工作。

In C, "what you see is what you get" often holds and the generated code is typically quite predictable, or better due to optimizations. 在C语言中,“所见即所得”通常成立,并且所生成的代码通常是可预测的,或者由于优化而更好。 But that kind of "magic" side-effect is really not how C tends to work. 但是,这种“神奇”的副作用实际上并不是C倾向于如何工作的。

It is probably better to not expose the "raw" register, but instead abstract out the existance of reserved bits: 最好不要公开“原始”寄存器,而是抽象出保留位的存在:

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

This explicitly computes reg in a way that sets the unused bits to 0. You might of course add asserts to make sure the 3- and 5-bit range limits are not exceeded. 这以将未使用的位设置为0的方式显式计算reg 。您当然可以添加断言,以确保不超过3位和5位范围限制。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM