1

我正在尝试使用 Cython 在我的 Python 代码中访问 C++ 全局变量。

假设我的 C++ 代码中有以下数组:

// Project.cpp
int myArr[2] = { 0, 1 };

因此,在 Cython 中定义一个指向myArr的指针:

cdef extern int * myArr_ptr

myArr_ptr真的指向C++ 数组吗?还是只是一个随机值?

4

1 回答 1

4

好的,问题是:

Project.cpp有一个全局int *myArr;的,它没有在 中列出Project.h,并且您想从 Cython 访问它而不导入Project.cpp.

在评论中,你说:

我无法包含 Project.cpp,因为该文件将尝试包含已包含的其他文件,并将尝试重新定义许多变量。

按照您描述的方式,这里可能存在一个基本错误。你可能知道这些基本的东西,所以请不要因为我提出它们而受到侮辱,但我只想彻底:

首先,如果你的头文件没有防止多重包含,修复它,然后你就不用担心“我不能包含Project.cpp,因为这个文件会尝试包含已经包含的其他文件,并且会尝试重新定义许多变量。” (如果您没有头文件,并且您只是在 .cpp 文件中使用显式extern语句执行所有操作,请不要这样做 - 在 C 和 C++ 中这是一个坏主意,在您开始之前Cythonizing。)

其次,如果您的模块旨在与作为其Project.cpp一部分的 .so/.dll/.dylib 接口,则您不应针对该库的源代码进行构建,而应针对已安装的接口进行构建。另一方面,如果您的模块打算直接包含 C++ 代码,那么您必须包含Project.cpp. 如果你使用extern声明来引用你不打算链接的东西,你只会得到一个链接器错误——或者,如果你不走运,一切都会构建,但在运行时会失败。

第三,如果它实际上不是全局的,则不能从外部访问Project.cpp——由于范围、生命周期或链接的原因,在单独的实现文件中没有其他类型的变量可用。

同样,我假设您知道所有这些基本知识,而我只是误读了您的评论。有一个真正的问题案例,您需要使用设计不佳的 API 来包装某些东西,这需要您进入内部,这有时会很棘手,您可能确实遇到过这样的事情,而我只是没有弄清楚到底是怎么回事。

有三个基本的解决方案。

首先,显然,如果您可以构建适当的原生 API,那么在 Cython 中包装该 API 是微不足道的。同时,由于其他原因,这很有用。有时,这会花费太多时间和精力——例如,如果本机库不是为外部驱动而设计的,并且需要 10 年的遗留维护,这是您必须打包的唯一原因它是当前的 Cython 项目,您可能不想清理它。或者,如果它是一个快速变化的库,您需要跟上它的更新并且没有源代码控制,那么分叉它并尝试保持同步可能是一场噩梦。等等。但是,如果您的情况没有这样的原因,那么这是正确的答案。如果可以cdef extern from "project.h",一切都很容易。

您可以通过在本机级别创建“shim API”来实现更简单的版本,.h为您需要从内部使用的各种函数和类型创建具有适当的外部、函数和类型声明的单独文件。然后,您可以cdef extern from "project_extras.h".

最后,您始终可以cdef extern为任何内容编写显式语句,而无需告诉 Cython 任何内容的来源。Cython 会在生成的代码中将其转换为适当的本机 extern,如果一切正确,它将起作用。这里有一些缺点-<a href="http://docs.cython.org/src/userguide/external_C_code.html#referencing-c-header-files" rel="nofollow">文档解释了所有优点cdef extern from你会放弃的。简短的版本是,您的 Cython 声明必须与本机声明完全匹配;否则,您不会在 Cython 阶段自动修复或引发一个不错的错误,而是会从 C 编译器收到一条难以理解的错误消息,指的是不可读的 Cython 生成的 C 代码,而不是您的实际代码——或者更糟糕的是,代码编译但做错了。

对于简单int *int []值的情况,所有这些都无关紧要,因为不需要任何解释;一个平原cdef extern应该就好了。

于 2013-01-09T19:41:57.893 回答