基本问题
我处于一个棘手的情况,需要获取指向结构的指针 mainset
并将其转换为指向结构体 subset
的指针,其字段是 mainset
字段的连续子集,从第一个开始。如果有明确的行为,这样的事情可能吗?我意识到这是一件非常可怕的事情,但我有充分且令人沮丧的理由这样做[在底部为耐心的读者解释]。
我尝试在 OS X 上使用 clang 编译器实现一个似乎可以工作的实现:
#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
与 &test+sizeof(test.reflex_size)
但这没有用; cout
的输出声明为 0。
解释为什么我必须这样做
我的项目使用 GSL 库进行线性代数。该库使用以下形式的结构
struct gsl_block {
size_t size;
double* data;
}
和类似的结构,如 gsl_vector
和gsl_matrix
。因此,我使用这些结构作为我的 C++ 类的成员;没问题。然而,我的项目最近需要的一个功能是使用 Reflex 启用对我的类的反射。工具,ROOT 生态系统的一部分。要在 Reflex 中启用这样的结构的反射,我必须添加一个注释,例如
struct gsl_block {
size_t size;
double* data; //[size]
}
此注释告诉 Reflex 数组的长度由字段 size
提供。相同结构的。通常是这样,但是 Reflex 和 ROOT 有一个非常不幸的限制:长度字段必须是 32 位。得知此限制不会很快得到修复,并且自己没有时间/资源来修复它,我正在寻找解决方法。我的想法是以某种方式嵌入一个与 gsl_block
位兼容的结构体在更大的结构中:
struct extended_gsl_block {
size_t size;
double* data; //[reflex_size]
uint32_t reflex_size;
}
以及gsl_vector
的类似内容和gsl_matrix
;我可以保证reflex_size
和size
总是相等(都不大于~50),并且 Reflex 将能够正确解析此 header (我希望;如果需要 reflex_size 作为字段放在数据之前,则需要更困难的东西)。由于 GSL 例程使用指向这些结构的指针,所以我的想法是这样的:给定一个指针 extended_gsl_block*
,以某种方式获取指向字段 size
的指针和data
和reinterpret_cast
这变成了gsl_block*
.
最佳答案
你很幸运。
您作为示例显示的类符合标准布局类型的要求。
您可以在这里阅读更多内容:
http://en.cppreference.com/w/cpp/language/data_members#Standard_layout
您可以在编译器中测试这个前提:
static_assert(std::is_standard_layout<gsl_block>::value, "not a standard layout");
关于c++ - 将指向结构的指针转换为具有较少数量字段的另一种结构类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43238780/