2017-04-05 76 views
2

基本問題鑄造一個指向一個結構到另一個結構類型以較小的一些領域

我在需要採取一個指向結構mainset並變成一個指向這一個棘手的情況是結構subset,其字段是mainset的字段的連續子集,從第一個開始。這樣的事情是否可能,具有明確的行爲?我意識到這是一件非常可怕的事情,但我有一個很好的和令人沮喪的理由來做這件事(底部爲患者讀者解釋)。

我嘗試的一種實現似乎工作,在OS X與鐺編譯:

#include <iostream> 

struct mainset { 
    size_t size; 
    uint32_t reflex_size; 
}; 

struct subset { 
    size_t size; 
}; 

using namespace std; 
int main(int argc, char *argv[]) { 
    mainset test = {1, 1}; 
    subset* stest = reinterpret_cast<subset*>(&test); 
    std::cout << stest->size << std::endl; 
} 

輸出確實是1,如我所料。然而,我想知道:我是否幸運地使用了一個特定的編譯器和一個簡單的案例(實際上我的結構更復雜),還是一般會工作?

而且,後續的問題:其他惱人的原因,我擔心我可能需要讓我的大結構

struct mainset { 
    uint32_t reflex_size; 
    size_t size; 
}; 

,隨之額外字段在前方傳來。我的實施可以擴展到在這種情況下工作嗎?我嘗試用&test+sizeof(test.reflex_size)替換&test,但這不起作用;在cout語句的輸出爲0

爲什麼我要做這個

我的項目使用GSL庫線性代數解釋。此庫利用形式

struct gsl_block { 
    size_t size; 
    double* data; 
} 

的結構和類似的結構像gsl_vectorgsl_matrix的。所以,我使用這些結構作爲我的C++類的成員;沒問題。然而,最近我的項目需要的功能是使用ROOT生態系統的一部分Reflex工具啓用我的課程。爲了使在反射像這樣的結構的反射,我必須添加註釋等

struct gsl_block { 
    size_t size; 
    double* data; //[size] 
} 

此註解告訴反射在於,所述陣列的長度由同一結構體的領域size提供。通常情況下, Reflex和ROOT有一個非常不幸的限制:長度字段必須是32位。被告知這個限制不會很快被修復,而且沒有時間/資源來自己修復它,我正在尋找解決方法。我的想法是一個更大的結構內以某種方式嵌入與gsl_block一個struct位兼容:

struct extended_gsl_block { 
    size_t size; 
    double* data; //[reflex_size] 
    uint32_t reflex_size; 
} 

gsl_vectorgsl_matrix類似的事情;我可以確保reflex_sizesize總是相等的(都不大於〜50)並且Reflex將能夠正確解析這個頭(我希望;如果reflex_size需要在數據之前作爲字段需要更困難的東西) 。由於GSL例程與指向這些結構的指針一起工作,我的想法是這樣的:給出指針extended_gsl_block*,以某種方式獲得指向sizedatareinterpret_cast這個字段的指針到gsl_block*

回答

2

你很幸運。

您作爲示例展示的類符合標準佈局類型的要求。

你可以在這裏閱讀更多:

http://en.cppreference.com/w/cpp/language/data_members#Standard_layout

您可以在編譯器測試這個前提:

static_assert(std::is_standard_layout<gsl_block>::value, "not a standard layout"); 
+0

謝謝!諮詢那個引用,盡我所能告訴所有我正在使用的類型都在標準佈局中,因爲所有的數據類型都是非靜態的和非引用的(因爲結構實際上都是C結構)。所以,希望我的運氣能繼續下去。下面可能會有更棘手的細節,尤其是關於如何爲這些結構分配內存的問題。 – jwimberley