2017-04-13 39 views
-1

这是一个远射,但也许会有一些想法。在我编程的系统中,我定义了结构来编程处理器寄存器。寄存器由几个位组成,每个位都有几个位,其间可能有“保留”位。写入寄存器时,保留位必须写为零。如何将预定义的值赋给类型定义上的结构成员?

例如:

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; 
} 

我希望能够给reserved字段设置为(在本例中为0)的默认值,并腾出一个明确的赋值需要(发生了很多我们的系统)。

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

+0

恐怕你不能。如果你的变量不是静态的,那么你需要明确地初始化它。 –

+1

关于位域的特定布局不能保证。如果你需要,他们不是一个好主意。改用'unit32_t'和shift/masking。你施放调用未定义的行为;你必须以不同的类型访问一种类型的对象!阅读有效类型(aka严格别名)规则。 – Olaf

+0

@Olaf - 在给定的实现(我们的嵌入式开发环境)中,行为应该被很好地定义(因为它恰好是)。我使用all-'uint32_t'结构的事实确保了这些字段是右对齐的,并且该结构的大小恰好是32位。 – ysap

回答

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; 
} 

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

+0

谢谢。是的,我发现这可能是不可能的,这就是为什么我在我的问题中说“远射”。我的做法是,我们使用宏来访问regs,屏蔽字段的大小。当你有多个寄存器时,你对接口函数的建议是不切实际的。 – ysap

2

结构型用C定义不能表达对结构成员的值。它没有任何机制。结构实例定义可以做。

我希望能够保留字段设置为默认值( 0这个例子),并腾出一个明确的赋值需要(这 发生了很多在我们的系统)。

注意,如果实例化的对象是静态的,则默认情况下的 未初始化的字段将是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 }; 

...但记住只使用指定成员初始化,如上,不是非指定值是非常重要的。

+0

谢谢。你的答案的第二部分(部分被入侵的对象的未初始化成员被设置为0)对我来说确实是新的。然而,这只是部分解决了我的问题(在这个例子中,只适用于保留位)。正如我所提到的,我想设置一个任意值。 – ysap

+0

我没有关注@ysap。你的意思是你想为整个结构默认初始化器,将一些成员初始化为非零值? –

+0

我想要* some *成员的默认初始化程序,但我不在乎default-init其他成员,因为这可以通过显式运行时初始化来重写。 – ysap

相关问题