【问题标题】:Expose a C++ global variable in Python在 Python 中公开 C++ 全局变量
【发布时间】:2012-12-22 22:10:03
【问题描述】:

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

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

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

所以,在 Cython 中定义一个指向 myArr 的指针:

cdef extern int * myArr_ptr

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

【问题讨论】:

  • 在 C++ 或 Cython 中,您尚未将 myArr 的地址分配给 myArr_ptr。事实上,你所做的一切都被定义为外部变量,所以我认为这甚至不会链接。但如果确实如此,是的,您将获得一个随机值——或者,由于它是一个随机指针值,因此将其称为等待中的段错误可能会更好。你是从某个地方复制的吗?如果有,在哪里? (知道这会让你更容易猜出你到底想做什么。)
  • 嗯..我明白了!不,我没有从任何地方复制它......我试图做的是在 Python 中访问 myArr 的元素。有什么办法可以存档吗?
  • 当然,访问其他内容的方式相同。是什么让您认为在末尾添加_ptr 是必要的或有帮助的?
  • 是的,但我没有 Python 上的数组。所以我不知道如何获得这些值。 _ptr 只是告诉它应该指向 C++ 中的 myArr
  • Cython 不会根据这样的名称做任何魔法。您可以通过将数组公开给 Python 来将其公开给 Python,或者您可以创建一个指向其第一个元素的指针,然后将其公开给 Python,或者您甚至可以直接将数组作为指针公开给 Python。只要you do it explicitly,您甚至可以进行神​​奇的重命名。我真的不明白你想在这里做什么。您是否阅读了教程和“外部声明”部分?

标签: c++ python arrays python-3.x cython


【解决方案1】:

好的,问题是:

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

在 cmets 中,你说:

我无法包含 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,如果一切正确,它将起作用。这里有一些缺点——the docs 解释了cdef extern from 的所有优点,你将放弃这些优点。简短的版本是,您的 Cython 声明必须与本机声明完全匹配;否则,您不会在 Cython 阶段自动修复或引发一个不错的错误,而是会从 C 编译器收到一条难以理解的错误消息,指的是不可读的 Cython 生成的 C 代码,而不是您的实际代码——或者更糟糕的是,代码编译但做错了。

对于简单的int *int [] 值,所有这些都无关紧要,因为不需要任何解释;一个普通的cdef extern 应该没问题。

【讨论】:

  • 哇...你涵盖了解决问题的所有可能方法,很好的解释!在您回答之前,我已经创建了一个单独的标题,就像您建议的那样,并且出于您上面指出的原因。我的问题没有反映实际问题,这是我想要的一个坏例子(在电脑上的时间太多+疲倦)。谢谢!!
猜你喜欢
  • 2015-11-22
  • 1970-01-01
  • 2016-04-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-24
  • 2015-06-12
  • 2011-07-28
相关资源
最近更新 更多