6

我想从 python 调用一个 c++ 函数,这个 c++ 函数以 char* 作为参数,并返回字符串。下面是我的代码。

包装器.cpp

#include <Python.h>
#include <string>
#include <iostream>

using namespace std;

extern "C"
string return_string(char* name){
    cout<<strlen(name)<<endl;
    cout<<name<<endl;
    string s = "hello ";
    s += name;
    return s;
}

将 wrapper.cpp 编译为 example.so

g++ -fPIC wrapper.cpp -o example.so -shared -I/usr/include/python2.7/

包装器.py

import os
from ctypes import *

lib = cdll.LoadLibrary('./example.so')
lib.return_string.restype = c_char_p
lib.return_string.argtypes = [c_char_p]
name = create_string_buffer("Tom")
s = lib.return_string(name);
print s
print name

这是我的输出

18
��H�L�l���A���
1
<ctypes.c_char_Array_4 object at 0x7f5f480be710>

如何使它起作用?

4

1 回答 1

11

这与 ctypes 无关;您的 C++ 代码本身无效。您不能定义extern "C"返回string.

在使用相同库的 C++ 程序的快速测试中,它也会打印垃圾。

我还编写了一个 C 程序,它定义了一些string具有相同布局的调用,std::string以便我可以编译它并查看会发生什么;它还打印垃圾,然后在~string.

因此,Python 程序也会打印垃圾也就不足为奇了。

稍作改动,一切正常:

extern "C"
const char *return_string(char* name){
    cout<<strlen(name)<<endl;
    cout<<name<<endl;
    static string s = "hello ";
    s += name;
    return s.c_str();
}

我得到这个输出:

3
Tom
hello Tom
<ctypes.c_char_Array_4 object at 0x11011c7a0>

(或者,在 C++ 版本中,同样的内容,但在最后一行带有“Tom”。)

当然,出于显而易见的原因,这不是一个很好的解决方案,但它表明返回string是问题所在。

当我尝试编译您的 C++ 代码时,g++-4.5 和 clang-apple-4.0 都警告过我这个问题(尽管 g++-apple-4.2 没有,除非我添加了一个额外的 -W 标志)。当编译器向您发出警告时,这通常是“为什么我的代码即使编译也会做错事”的答案。

您的代码还有其他一些问题:

  • 您不会在 .cpp 文件中使用 Python 中的任何内容。总的来说,使用的全部意义ctypes在于让你的 C 或 C++ 代码不必了解任何关于 Python 的知识。是你的 Python 代码知道它。所以,不要包含或链接。
  • char*如果您不打算修改它,那么采用非常量通常是一个坏主意。const_cast<char*>(name.c_str())我的 C++ 驱动程序必须使用而不是仅调用它name.c_str()。此外,这可以防止编译器注意到您正在做的其他事情。

这是我上面提到的 C++ 驱动程序:

#include <iostream>
#include <string>
using namespace std;

extern "C" string return_string(char* name);

int main(int argc, char *argv[]) {
  string name("Tom");
  string s(return_string(const_cast<char *>(name.c_str())));
  cout << s << "\n";
  cout << name << "\n";
  return 0;
}

此外,如果我在我的 C++ 驱动程序中使用不同的优化设置或稍微重新组织代码,有时您的代码实际上可以工作,有时它会打印垃圾,有时它会出现段错误。我的第一个猜测是,这取决于~string调用的内联位置——但实际上,细节并不重要;代码不应该工作,它没有,所以谁在乎为什么?

于 2012-09-19T18:00:13.193 回答