2011-04-04 68 views
7

比方說,我有這幾種:如何做一個靜態聲明指針轉換是微不足道的?

struct A { 
    int a; 
}; 

struct B { 
    int b; 
}; 

struct C : public A, public B { 
    int c; 
}; 

一個C*指針可以轉換爲A*指針,而完全不調整的實際地址。但是,C*投射到B*時,值必須更改。我希望確保兩個相關的類型可以在不改變地址的情況下相互轉換(即沒有多重繼承,或者基類是派生類的第一個基類)。這可以在運行時檢查,例如,像這樣

assert(size_t(static_cast<A*>((C*)0xF000) == 0xF000); 
assert(size_t(static_cast<B*>((C*)0xF000) != 0xF000); 

這是行得通的。但是這些信息在編譯時是已知的,所以我正在尋找一種編譯時斷言的方法。轉換上述靜態斷言(例如替換assertBOOST_STATIC_ASSERT給錯誤「的鑄造到不是整型或枚舉類型之外的類型不能出現在恆定表達」使用g ++ 4.2。

可移植性的明顯的方式是不是太重要使用gcc的擴展,或者哈克模板招數都將是罰款

更新:。發現,幾乎同樣的問題以前有人問:C++, statically detect base classes with differing addresses?使用offsetof()是那裏唯一有用的建議了。

+8

不想成爲一個挑剔的人,但因爲確切的內存佈局是一個實現細節......你爲什麼會對這個完全感興趣? – 2011-04-04 06:23:57

+0

我很確定Boost/lambda庫包含這個東西。我不得不去查看它,但Alexandrescu和Vandervoorde已經發布了這個領域的所有技巧 – sehe 2011-04-04 06:39:03

+0

我真的對@Matthieu M.提出的問題感興趣:如果演員陣容可以變得微不足道,那麼在什麼情況下呢? (即如果它不平凡,成本可能可以忽略不計:給派生指針增加一個常量,如果條件沒有正確完成,你會遇到真正的痛苦,試圖調試看起來像損壞的內存) – 2011-04-04 07:47:44

回答

1

根據MSalters的建議和C++, statically detect base classes with differing addresses?的回答,這裏是最接近我能想出答案的答案。這也可能是GCC特有的,需要知道基類的一些成員:

#pragma GCC diagnostic ignored "-Winvalid-offsetof"  // To suppress warning. 
BOOST_STATIC_ASSERT(offsetof(C, a) == offsetof(A, a)); 
BOOST_STATIC_ASSERT(offsetof(C, b) != offsetof(B, b)); 
#pragma GCC diagnostic warn "-Winvalid-offsetof" 

顯然,這既不方便嚇人(需要知道的成員,並關閉警告)。

4

「我想確保兩個相關類型可以相互轉換而不改變地址(即,沒有多繼承,或者基類是派生類的第一個基類)「

你的」ie「不正確,例如,Derived的前4個字節完全可能是一個vtable指針,即使Base不是多態。是的,如果(1)第一個基礎子對象在偏移0處,並且(2)vtable指針在偏移0處,C++編譯器更容易。但是這兩個目標本質上是目前還沒有明確的更好的選擇

現在,第一部分可以在理論上測試,在標準佈局類型中,offset_of(Base, first_member)offset_of(Derived, first_member)沒有差別,但實際上offset_of不起作用爲有趣的類型; UB。此檢查的重點是檢查類型,因此對於非標準佈局類型它應該可靠地失敗。

+1

「你不能檢查,因爲它不是真的」。我的意思是,因爲它並不總是如此,我需要能夠檢查!現在,(C,a)想法的偏移聽起來非常有希望,但gcc抱怨「無效訪問非靜態數據成員A :: a'的NULL對象。」 – 2011-04-04 15:14:30

+0

其實,海灣合作委員會的投訴是一個警告,而不是一個錯誤。所以當基地的第一個成員知道時,這確實起作用。這是事。謝謝! – 2011-04-04 15:33:52

+0

我編輯了MSalters的評論「你不能檢查,因爲它不是真的」,我認爲更清晰的「你的」即'是不正確的「。我不認爲MSalters可能會試圖說你的整個陳述是錯誤的。根據他的下一句話,我認爲他的意思是「兩種相關的類型可以......」實際上並不等同於「沒有多重繼承......」。 – Quuxplusone 2013-12-19 19:07:28