2015-02-11 91 views
1

我目前正在編寫一個基本的操作系統作爲一個學習項目。爲此我使用了gcc 4.9.2交叉編譯器。 當試圖使用存儲器映射的I/O I偶然發現C指針(或可能存儲器映射I/O),我無法理解的行爲。 當通過下面的代碼直接訪問I/O存儲器,I得到預期的結果,這是一個「AB」在黑色背景上的淺灰色字體的左上角。奇怪的行爲映射I/O

*((uint16_t *)0xB8000) = 0x0741; 
*((uint16_t *)0xB8002) = 0x0742; 

但是試圖通過使用偏移添加2基地址來操縱存儲器當結果沒有作爲在第二但在第三位置預期的「A」。

*((uint16_t *)0xB8000 + 2) = 0x0741; 

添加1而不是2打印第二個位置的字母,但我不明白爲什麼。由於每個字母(在MMIO中)由2個字節的數據組成,因此我認爲我需要將我寫入的內存地址增加2,以便爲下一個字符。 (正如我在第一次做直接寫入0xB8002) 爲了嘗試和理解這種行爲,我做了一個單獨的C程序的一些測試,但無法複製這種行爲: (注:此代碼被編譯使用普通的gcc 4.8 0.2)

#include <stdint.h> 
#include <stdio.h> 

void main(void) { 
     printf("0xB8000 + 1 = %x\n", 0xB8000 + 1); 
     printf("&(*(uint16_t *)(0xB8000 + 1)) = %x\n", (uint32_t)&(*(uint16_t *)(0xB8000 + 1))); 
} 

這個程序產生的輸出如下:

0xB8000 + 1 = b8001 
&(*(uint16_t *)(0xB8000 + 1)) = b8001 

我認爲我缺少某種C指針的行爲,這將導致保理在由寫入的數據的大小一份聲明。這是這種情況還是我有忽略的另一個原因?

問候,Kenshooak

+2

你可能會受益於重新讀指針運算基礎(總是由基本型縮放)。或者,也許運算符優先級(強制轉換優先級高於「+」)。 – Deduplicator 2015-02-11 18:23:34

+0

此外,您可能需要使用'volatile'這裏,以確保編譯器不自作聰明,優化作業了。 – 2015-02-11 18:49:49

回答

4

如果添加到<type>指針的地址是由sizeof(<type>) * n字節遞增的整數n。 所以在你的第一個例子,你有

*((uint16_t *)0xB8000 + 2) = 0x0741; 

等什麼這裏發生的情況是:0xB8000被轉換爲unit16_t *,然後該指針遞增2,這意味着2 * sizeof(uint16_t) = 4個字節

在第二個例子中,你有

*(uint16_t *)(0xB8000 + 1) 

注意不同的包圍:在這裏你首先加1到0xB8000--一個簡單的整數運算 - 然後轉換結果。

+0

非常感謝,我完全錯過了不同的包圍可能會對結果產生影響! – kenshooak 2015-02-11 18:40:13