2014-10-02 67 views
4

我在嵌入式目標上工作,並想定義內存池。內存地址表示爲void*。但是,在特定情況下,這些地址會被緩存,我想解壓縮它們以直接獲取「真實」硬件地址。如何將遮罩應用於const void *地址?

我想定義的memory_area開頭的地址(這僅僅是一個標記):

#define UNCACHE_MASK 0xABCDEF12UL // Value of the mask to apply 
extern uint32_t memory_area; // Global, defined somewhere else 
const void * virtual_address = &memory_area; // OK 
const void * real_address = 
    (void*)(virtual_address | UNCACHE_MASK); // guilty line 

不幸的是,GCC不會讓我這樣做:

error: invalid operands to binary | (have 'const void *' and 'long unsigned int') 

無奈之下我試過了:

const void * real_address = 
    (void*)(((uint32_t)virtual_address) | UNCACHE_MASK); // guilty line 

枉然:

error: initializer element is not constant 

我真的想保持const的安全:是否可以實現?

[編輯]

  • 我在Linux上使用gcc V4.9(與-std=gnu99和很多-Wxxx標誌)。
  • 摘錄來自.h文件,變量是「全局」。
+2

這裏它可能並不重要,你知道你的拱是32位的,但通常你應該使用'uintptr_t'來將指針轉換爲整數。 (因爲你把你的東西移植到64位的那一天,你會後悔:) – 2014-10-02 12:38:39

+0

對,謝謝你的提示! – Coconop 2014-10-02 12:48:03

+0

我不認爲「緩存」意味着你認爲它在這裏。這聽起來好像你在談論虛擬地址*,這不是一個緩存概念。緩存不會更改地址。 – unwind 2014-10-02 13:01:54

回答

2

您可以在函數中使用您的按位或表達式來分配它。你不能像在前面所說的那樣在全局範圍內進行初始化,因爲編譯器不知道該值(可能在C++中,但不在C中)。如果添加了強制轉換並將其分配到一個函數作用域中,它將起作用。

當你這樣說:

const void * real_address 

這意味着「real_address是指向未知類型的常量的記憶。」如果您希望指針也不可修改(除了它所指向的),你可以這樣做:

const void * const real_address 

但你不能因爲你需要將其初始化函數內部做。我想你可以拋棄函數內的常量,但這在C中甚至可能不合法。

+1

如果你定義了'void const * const',就不可能在函數中給'real_address'賦值。 – user694733 2014-10-02 12:09:00

+0

@ user694733:謝謝,我解決了我的答案以反映這一點。 – 2014-10-02 13:19:11

+0

我終於選擇了放棄'const',只是將其聲明爲全局函數並在函數中設置地址。 – Coconop 2014-10-06 08:29:32

5

只需定義一個。它不能被意外改變。

#define real_address ((void*)((uint32_t)virtual_address | UNCACHE_MASK)) 

每個用法的額外指令或兩個不是很昂貴。

此外還添加一個const關鍵字virtual_address變量,所以它不能改變。

const void* const virtual_address = ... 
+0

好的提示,它實際上解決了我的代碼摘要上的問題,但是我正在尋找優化和'real_address'用於其他計算其他地方,我想要避免這些額外的指令。 – Coconop 2014-10-02 13:49:07

+1

如果這個重新計算真的是一個瓶頸(我懷疑它),你可以嘗試在變量的開頭存儲一次值。如果你經常使用該變量,它應該總是在緩存中很熱,並且在重新加載時不會產生很多開銷。 – 2014-10-02 13:54:47