2010-12-09 86 views
3

我想訪問硬件寄存器(64位,只有40個LSb的地址)中的地址所指向的32位數據。所以,我做的:當指針和數據寬度不同時指針間接尋址

paddr_t address = read_hw(); // paddr_t is unsigned long long 
unsigned int value = *(unsigned int*) address; // error: cast to pointer from integer of different size 
unsigned int value2 = (unsigned int) *((paddr_t*) address); // error: cast to pointer from integer of different size 

會是什麼正確的方式來做到這一點沒有編譯器錯誤(我用-Werror)?

回答

1

名義上與C99的第一選擇是最接近正確,

uint32_t value = *(uint32_t*)address; 

然而,你也可以選擇使用其他的指針/整數幫手,

uintptr_t address = read_hw(); 
uint32_t value = *(uint32_t*)address; 
0

檢查實際尺寸爲您的指針和paddr_t類型:

printf("paddr_t size: %d, pointer size: %d\n", 
     sizeof(paddr_t), sizeof(unsigned int *)); 

你會得到什麼?

更新:

ARM是32位架構,讓你嘗試從一個64位整數轉換爲32位指針的編譯器不喜歡它!

如果你確信在paddr_t值在32位指針適合你可以將它轉換爲第一的int

unsigned int *p = (unsigned int *)(int)addrs; 
+0

我沒有補充說我正在使用交叉編譯器。所以我沒有printf的奢侈! – Jeenu 2010-12-09 08:52:25

0

我不知道我理解的問題。 「我想要訪問硬件寄存器中的地址指向的32位數據(它是64位,只有40 LSb的設置)」。

因此,您有一個64位寬的硬件寄存器,其中最不重要的40位應該被解釋爲內存中包含32位數據的地址?

你可以嘗試

uint32_t* pointer = (*(uint64_t *) register_address) & (~0 >> 24) 
uint32_t value = *pointer 

雖然這可能會依賴於字節序和是否編譯器把>>爲邏輯或算術右移更加複雜。

雖然,說真的,我想問一下,

  1. 請問「我使用的是交叉編譯器,我沒有的printf的奢侈品」的意思是你不能真正運行代碼,或只是你必須做一些缺乏方便的輸出通道的硬件?
  2. 你的目標架構是什麼,你的指針長度是40位?!
0

從你寫的你有一個64指針,其中只有40位是指針,該指針指向一些32位大小的數據。

您的代碼似乎試圖將40位指針壓入32位指針。

什麼,你應該做的是&「荷蘭國際集團的64位指針中的相關40位的,所以它仍然是一個64位的指針,然後使用來訪問數據,然後你就可以同樣&獲取數據。否則你是(如錯誤指示)截斷指針。

喜歡的東西(我沒有64位,所以我不能對此進行測試,但你的想法):

address = address & 0x????????????????; // use the ?s to mask off the bits you 
             // want to ignore 
value64 = *address; // value64 is 64 bits 

value32 = (int)(value64 & 0x00000000ffffffff); // if the data is in the lower 
               // half of value64 
or 
value32 = (int)((value64 & 0xffffffff00000000) > 32); // if the data is in the 
                 // higher half of value64 

,其中根據需要的是屏蔽位(視?你正在使用的終結)。您可能還需要更改(int)強制轉換以適應(您希望將其強制轉換爲數據表示的任何32位數據類型 - 即value32的類型)。