2017-04-20 48 views
1

dlsym()man page名單對dlsym()的解決方法返回類型

*(void **) (&cosine) = dlsym(handle, "cos"); 

作爲用於鑄造的dlsym()返回值一種解決方法。

*(void **) (&cosine)這是什麼意思?據我所知cosine是一個先前定義的函數指針,但我不知道爲什麼在名稱前需要使用&符號&(錯誤沒有&)。此外,我不知道爲什麼指針void *void **)再次與*一起使用。

+0

這裏假設一個'double(* cosine)(double);'或類似的聲明。 – ephemient

+0

非常常見的問題。如果數據指針和代碼指針的大小相同,這個「解決方案」完美地工作。否則它會失敗壯觀。 –

+0

@LorinczyZsigmond你一般都是對的,但是'dlsym'特別來自POSIX,它要求這在合適的實現中起作用。換句話說,POSIX只允許具有平坦內存模型的平臺,其中所有指針都是相同的。 – ephemient

回答

2

讓我們來解開這一點在一個時間:

&cosine 

這需要一個指針變量cosine,所以這將是一個指向一個函數指針。

(void **) &cosine 

我們將指向函數指針的指針轉換爲指針指向void的指針。

* (void **) &cosine 

我們取消引用指針鑄造,分配的dlsym()到它的結果。

實際上,發生的事情是問題的一個側面步驟。我們假設cosine是一個void *(通過間接級別)並分配給它,而不是將dlsym()的結果轉換爲正確類型的函數指針。

+0

沒錯。 C沒有定義數據指針和函數指針之間的轉換。定義'void * dlsym(const char *,int)'的POSIX確實意味着可以在'void *'中表示一個函數指針(這是一個在標準C中沒有做出的保證),但是它不會'避免將一個'void *'強制轉換爲函數指針的事實沒有明確定義。在這裏,'&cosine'是一個數據指針(指向一個函數指針),並且允許通過'void *'投射一個數據指針,所以這使我們保持安全。 – ephemient

+0

非常明確的解釋。謝謝! –

+0

@ephemient,你確定它解決了這個問題嗎? 'void *'和'double(*)(double)'似乎不是兼容的類型,所以這會違反嚴格的別名規則,而不是依賴於可以轉換爲void *的函數指針。違反嚴格的別名會導致UB,但編譯器有真正的機會在不正確的顯式轉換中發出警告/錯誤。在我看來,如果編譯器允許你這樣做,而不是在運行時由於UB而可能中斷,那麼你最好進行轉換並靜態檢查。 – zneak