2015-03-13 71 views
4

我在寫一些將虛擬地址映射到物理地址的代碼。可以比較C中的指針和整數嗎?

我沿着這些線路代碼:

if (address > 0xFFFF) 
    Status = XST_FAILURE; // Out of range 
else if (address <= 0xCFFF || address >= 0xD400) { 
    // Write to OCM 
    Xil_Out8(OCM_HIGH64_BASEADDR + OCM_OFFSET + address, data); 
else { // (address >= 0xD000) 
    // Write to external CCA 
    Status = ext_mem_write(address, data); 

我得到一個編譯器警告: comparison between pointer and integer [enabled by default]

我意識到,我比較了兩種不同類型(指針和整數),但是這是一個問題?畢竟,比較指向一個整數的指針正是我想要做的。

定義指針常量來比較而不是整數會更清晰嗎?

const int *UPPER_LIMIT = 0xFFFF; 
... 
if (address > UPPER_LIMIT){ 
    .... 
+3

最好將指針轉換爲整數,而不是將整數轉換爲指針。這是因爲指針的比較運算符沒有很好的定義,但是對於它們的整數。 – 2015-03-13 19:30:15

+2

指針通常是一個無符號整數,將其與有符號整數進行比較可能會由於轉換而產生意外的結果。 – dtech 2015-03-13 19:31:05

+0

一旦您確信自己所做的工作,使用強制轉換來擊敗編譯器警告,而不是禁用警告。但只有這樣;)。也許從@EugeneSh實施建議。將刪除警告。 – 2015-03-13 19:34:05

回答

3

乾淨的方法是使用uintptr_t類型的常量,它被定義爲一個無符號整數,可以在指針和整數之間唯一映射。

這應該由#include <stdint.h>定義。如果未定義,則表明您的編譯器不遵循C標準,或者系統沒有平坦的內存模型。

它旨在以「明顯」的方式進行映射,即每個字節按升序排列一個整數。該標準並不能絕對保證,但作爲實施問題的質量,很難看到其他事情發生。

實施例:

uintptr_t foo = 0xFFFF; 

void test(char *ptr) 
{ 
    if ((uintptr_t)ptr < foo) 
     // do something... 
} 

這是由C標準明確定義。您使用void *而不是uintptr_t的版本是未定義的行爲,儘管如果您的編譯器不太具有侵略性,它可能會工作。

+0

嗯。我試過這個,我仍然得到同樣的警告。 – Spark 2015-03-16 20:48:03

+0

@Spark仔細檢查你的代碼,這段代碼不會給出警告。也許警告來自你的代碼的另一部分。 – 2015-03-16 21:04:51

+0

啊哈 - 我忘記了(uintptr_t)在指針上的投射。 – Spark 2015-03-17 13:18:38

2

這可能是爲什麼Linux內核使用unsigned long的地址(注意區別 - 指針指向的對象,而地址是在內存中的位置代表一個抽象的代碼)。

這是從編譯器的角度如何看起來:

  1. C標準沒有定義如何比較int(算術型)字面0xFFFF和指針address - 見第6.5.8
  2. 所以,它必須以某種方式轉換操作數。這兩種轉換的實現都定義爲段落6.3.2.3的狀態。這裏有幾個瘋狂的決策,編譯資格做:
    • 因爲0xFFFF可能是int - 見6.4.4,它可能會強制將指針int,如果sizeof(int) < sizeof(void*),你將失去高字節。
    • 我能想象的要多瘋狂的情況下,當0xFFFF被符號擴展至0xFFFFFFFF(不應該,但爲什麼不)

當然,沒有(2)應該發生的,現代的編譯器是聰明足夠。但它可能會發生(我假設你正在編寫嵌入的東西,它更可能發生),所以這就是編譯器提出警告的原因。

這裏是「瘋狂的編譯器的事情」一個實際的例子:在GCC 4.8優化開始治療整數溢出爲UB(未定義行爲),省略說明假設程序員不希望整數溢出https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61569

我指的是N1570 - C11標準草案

+1

第2點是錯誤的;任何試圖比較指針和整數的代碼都是不合格的。程序員必須使用轉換來選擇一個選項。 – 2015-03-13 21:04:20

+0

@MattMcNabb,但如果程序員不這樣做,編譯器必須決定如何處理這種情況。所以第2點描述了潛在的克服。 – myaut 2015-03-13 21:13:28

-1

角色指針無符號整型,以避免警告:(unsigned)address - 在32或16位的地址空間的情況下。

+2

爲此目的存在可選類型'uintptr_t';它保證足夠大以容納一個指針。 – 2015-03-13 21:03:33