我正在使用第三方C ++库在Julia中进行一些繁重的工作。在朱莉娅方面,数据存储在类型为Array{Float64, 2}
的对象中(这与二维双精度数组相似)。我可以使用指向double
的指针将其传递给C ++。但是,在C ++方面,数据存储在名为vector3
的结构中:
typedef struct _vector3
{
double x, y, z;
} vector3;
我的快速而肮脏的方法是一个五步过程:
double*
复制到vector3*
vector3*
复制到double*
复制大量数据效率很低。有什么奥秘的技巧可用来避免将数据从double
复制到struct
并返回?我想以某种方式将double
的1D数组(大小为3的倍数)解释为具有3个double
成员的结构的1D数组。
答案 0 :(得分:3)
严格来说,您不能。不久前,我曾问过类似的问题(Aliasing struct and array the C++ way),答案解释了为什么直接别名会调用未定义的行为,并给出了一些可能的解决方法的提示。
话虽这么说,您已经陷入困境,因为原始数据来自另一种语言。这意味着该数据的处理未包含在C ++标准中,仅由您使用的实现(gcc / version或clang / version或...)定义。
对于您的实现,将外部数组别名为C ++结构或将外部结构别名为C ++数组可能是合法的。您应仔细阅读混合语言编程的文档,以实现精确的实现。
答案 1 :(得分:2)
不幸的是,您不能。这是因为C ++具有aliasing rule。简而言之,如果您有对象T
,则不能从不兼容类型U
的指针合法访问它。从这种意义上说,您无法通过类型为double
的指针访问类型为double*
或struct _vector3
的对象,反之亦然。
如果深入研究,您会发现reinterpret_cast
并可能认为“哦,这正是我需要的”,但不是。无论您采取什么欺骗手段(reinterpret_cast
或其他方式)来绕过语言限制(也称为只需使其编译),事实仍然是您可以合法访问类型{{ 1}}仅通过类型double
的指针。
一种经常用于类型调整的技巧是使用double
。在union
中合法,但是在C ++中是非法的,但是某些编译器允许这样做。但就您而言,我认为没有办法使用联合。
理想的情况是直接对C
数据进行繁重。如果在您的工作流程中可行的话。
答案 2 :(得分:0)
其他答案提到了实际问题(转换可能无法正常进行)。我将添加一个小的运行时检查,以验证别名是否有效,并提供一个占位符,您可以在其中调用/使用繁重的代码。
int aliasing_supported_internal() {
double testvec[6];
_vector3* testptr = (_vector3*)(void*)testvec;
// check that the pointer wasn't changed
if (testvec != (void*)testptr) return 0;
// check for structure padding
if (testvec+3 != (void*)(testptr+1)) return 0;
// TODO other checks?
return 1;
}
int aliasing_supported() {
static int cached_result = aliasing_supported_internal();
return cached_result;
}
此代码将一小部分的double转换为别名为结构的数组(不复制),然后检查其是否有效。如果转换有效(该函数返回1),则您自己可能会使用相同的别名(通过void指针转换)。
请注意,该代码仍会被意外破坏。严格的别名规则规定,即使上述检查也是未定义的行为。这可能会起作用,或者可能会严重失败。只有允许正常工作的转换才是void *并返回到原始指针类型。同样,上述检查在多个继承层次结构或虚拟基类中可能是完全错误的(从某种意义上来说,两者都不安全地转换为void *,因为实际的指针值可能会发生偏移,也就是说,由于对齐以外的约束可能会发生更改)并且有很多字节)