2017-04-05 82 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