2011-07-26 103 views
4

我在寫一個Linux內核模塊,它利用了輸出符號open_exec鑄造指針在64位拱警告

struct file *open_exec(const char *name) 

它返回一個指針,我可以檢查與錯誤整數問題IS_ERR宏:

if (IS_ERR(file)) 
    return file; 

在編譯的時候,我得到這樣的警告:

warning: return makes integer from pointer without a cast 

這是因爲我的函數在這裏返回一個整數。如果我嘗試投它:

return (int) file; 

我沒有得到我的32位機器上的警告,但我做我的64位計算機上:

warning: cast from pointer to integer of different size 

這是因爲一個int的sizeof和指針在32位上是相同的,但是在64位機器上它們是不同的。

無論是否投射,代碼似乎都有效。我只想擺脫這個警告。

我該如何正確轉換爲一個整數的指針並獲得我期望的值,同時沒有得到編譯器警告?我期望的值基本上是在Linux內核代碼庫的include/asm-generic/errno-base.h中列出的一個整數。

因爲我只看着指針就好像它是一個整數,在IS_ERR()爲真的情況下,我可以確定它實際上只保存一個整數值。

+0

警告是有道理的:如果INT無法容納一個指針,你的代碼可以得到麻煩;可能它不會,但你不能確定;如果你的函數必須返回一個指針,你爲什麼使用int作爲返回類型? – ShinTakezou

+0

,因爲在那裏我返回一個錯誤的案件95%,我知道是什麼錯誤,並將其指定(即,返回-EPERM)。對於可能出錯的函數,返回一個指針,我想提取錯誤是什麼,並報告。 –

+1

我無法得到它;在返回之前「提取」錯誤,將其映射到一個int,並返回該int ...爲什麼不呢?或者,在產生它的func內報告錯誤;反正,不要混用整數和指針,即使是在32位不好(你怎麼能肯定的地址不偶然匹配-EPERM?) – ShinTakezou

回答

8

PTR_ERR()linux/err.h,這就是IS_ERR()也被定義,將一指針這真的錯誤代碼轉換成適當的類型(一個long)。

你應該使用類似:

if (IS_ERR(file)) 
    return PTR_ERR(file); 

搜索源的PTR_ERR()現有用途,你會看到這是一個常見的模式。

您的函數返回一個long而非int這可能是適當的 - 但所有的錯誤代碼應該是一個int表示的。

+0

看起來像是做這項工作,我甚至不需要施展它。謝謝! –

+0

是的。很遺憾,其他答案是怎麼錯了...從來沒有想過檢查API或意識到這必須是一種常見模式。 –

+2

@Jim:說實話,我誤解了一開始真正被問到的。如果沒有在非錯誤情況下'file'指針發生的情況,可以很容易地得出結論,指針在正常情況下返回爲int。然後你會從問題的真正要求中分心。 –

1

您不能正確投出指向一種較小的大小,類型的指針。如果您確定該指針存儲了什麼,則可以進行一些轉換。例如,如果你知道一個指針只有最低32位的設置,你可以直接使用它並使用一些編譯器專用的編譯指示來抑制警告。或者,如果您想散列指針以用於類似散列表的指針,則可以使用較低的32位異或高32位。

如果不知道以後如何使用int,則無法確定。

+0

我打算在這裏出現一個肢體,並說我完全確定指針,在IS_ERR的情況下)是真實的,包含errno-base.h中的一個值 –

+0

這樣做的例子會很棒:-D –

+0

@Corey Henderson:假設你確定'int'足夠寬。然後'(int)(intptr_t)value'將是我想要的方式。如果警告仍然存在,請查找如何抑制它。 – sharptooth

0

我不知道我是如何得到你有時想從errno-base.h返回一個數字,有時候還有一個指針 - 接收函數如何能夠將兩者區分開來?即等於,然後在Linux GCC,

  • int是32位寬,不論是否是在32或64位 linux的
  • 指針是64位寬的上64位體系結構,和32咬寬上 32 bit體系結構
  • long在32位體系結構上爲32位寬,在64位 體系結構上爲64位寬。
  • long long總是64位寬

因此在64位架構把指針爲int意味着你將區分64位值的32位值,並且可以在一定程度上肯定,你會失去一部分來自指針的64位信息 - 這就是編譯器警告的全部內容,正如你指出的那樣。

如果你想從一個指針轉換爲東西「匿名」,那麼你的選擇應該是longlong longvoid* - 與void*是最便於攜帶。

另一種方法是記錄它作爲一個偏移量,也就是說,如果你有,你想「投」到32位整數一個大的存儲區域,然後將其轉換爲類似;

static struct mybigbuffer *globalbuffer; 
    int cast2int(void*x) 
    { 
     return (int)(globalbuffer-(struct mybigbuffer*)x); 
    } 

然而是只有工作假設你知道,你的記憶永遠不會超過2^31個記錄globalbuf和您的指針放心邊界上對齊等 - 因此,除非你100%確定你知道你在做什麼,我不會推薦這個 - 堅持長或無效*作爲安全選項。

+0

我不知道在內核上下文中提供的類型,但通常以C有'[u] intpr_t'指針指向整數轉換。 –

+0

聽起來更好...... – Soren