2017-04-13 97 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

相關問題