【问题标题】:different programming language and calling convention不同的编程语言和调用约定
【发布时间】:2012-02-07 02:54:16
【问题描述】:

根据维基:

不同的编程语言使用不同的调用约定,并且 不同的平台(CPU架构+操作系统)也可以。这 组合模块时有时会导致问题 多种语言

那么当我在 Python 中调用 C/C++ 函数(从 .so/.dll 导出)时,我应该小心吗? 如果是,我应该注意什么?

【问题讨论】:

  • 你用什么工具从 Python 调用 C++ 函数?
  • @EthanSteinberg,可能是 ctypes。

标签: c++ python c calling-convention


【解决方案1】:

Python 和 C 之间的调用是一个已解决的问题,因此您通常不必担心任何事情——尤其是因为 Python 是用 C 编写的。

当平台上的多种语言全部独立开发,从汇编程序单独引导时,所描述的问题会更加严重。例如,在 C 和 FORTRAN 之间以及 C 和 Pascal 之间的调用曾经有著名的问题,当时这三种语言大致平等地共存。旧的 Mac Toolbox 主要是使用 Pascal 调用约定在汇编程序中编写的,早期的应用程序开发人员使用 Borland Pascal。但是后来出现了像 Symatec 的 THINK C 这样的 C 编译器,那些程序员不得不特别担心如何翻译参数类型和字符串约定(Pascal 字符串在开头带有一个长度字节,当然 C 字符串在结尾有一个 0。)

【讨论】:

    【解决方案2】:

    从 python 调用 C 时,调用约定不是问题,因为 python 解释器本身是用 C 编写的,因此使用与 C 代码相同的调用约定。

    当组合使用不同编译语言(例如 C 和 Ada)编写的代码时,这会成为一个问题。

    通常 C 是系统编程语言,因此是标准。这意味着任何语言的编译器通常都具有与 C 互操作的特殊支持。有关 C 和 Ada 之间互操作性的示例,请参见here。如果没有特殊的支持,包装器必须在汇编级别编写。

    如果您需要从 python 调用 C++/Ada,您必须遵循两个步骤。第一步是围绕 C++/Ada 函数编写 C 包装器。第二步是从python调用C封装。

    以下面的 C++ 类为例。

    class Foo
    {
    public:
      Foo ();
      int bar ();
      ...
    };
    

    如果你想让它对python可用,你首先需要将它包装在C中:

    extern "C" {
    typedef void *FooPtr;
    FooPtr foo_new () { return (FooPtr)new Foo(); }
    int foo_bar (FooPtr foo) { return ((Foo*)foo)->bar(); }
    ...
    }
    

    然后你可以从 python 调用它。 (请注意,在现实生活中,有一些工具可以自动执行此操作,例如 Boost.Python)。

    请注意,编写包装器有两个方面:调用约定之间的转换和类型表示之间的转换。后面的部分通常是最困难的,因为一旦你超越了基本类型,语言就会对等价类型有非常不同的表示。

    【讨论】:

    • 那么,如果我从 Ada 调用 C,应该注意什么以及如何处理?
    【解决方案3】:

    C 和 C++ 有不同的调用约定。 C 不支持调用 C++ 函数,但 C++ 支持调用 C 函数并支持在 C++ 中实现 C 函数。也就是说,您可以在 C++ 中将函数声明为 extern "C"。我不知道 python 绑定是如何调用 C++ 的,但是你应该小心地使用它们各自的调用约定来调用 C 和 C++ 函数。通常,在不同语言之间调用时使用 C 调用约定。这可能意味着您可能需要使用 C++ 风格函数的 C 风格约定编写包装函数。

    【讨论】:

    • 您指的是用于链接的名称修饰,而不是调用约定。
    • 不,我指的是不是! C 和 C++ 之间的函数调用约定可能不同。请参阅 7.5 [dcl.link] 了解我在说什么。
    • 是的,但这很令人困惑,在 C 中包装 C++ 调用的典型原因是因为名称修改,而不是因为调用约定。使用某些编译器,您可以声明函数的调用约定,它将编译为该约定。这通常用于与使用不同于标准 C 的调用约定编译的共享库兼容。
    • 我没有看到任何混淆:不同的名称被不同的调用约定所包含。然而,值得注意的是,即使与损坏的系统完全匹配,如果它与函数调用方式的确切细节不匹配,您也不会总是乐意调用该函数。
    • 经过更多研究后,C 和 C++ 都使用相同的调用约定:cdecl。将 C++ 调用包装在 C 包装器中的原因是名称修改,没有其他原因。见:cplus.about.com/od/introductiontoprogramming/a/…
    【解决方案4】:

    调用约定是指在结果程序集中如何生成函数调用。一种约定是调用者负责为局部变量创建和清理堆栈空间。另一个约定是被调用函数为局部变量创建和清理堆栈空间。使用哪一个并不重要,但显然它们必须匹配,否则堆栈会损坏。

    您可以在此处查看更多详细信息:http://en.wikipedia.org/wiki/Calling_convention

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-28
      • 2020-08-23
      • 2013-09-19
      • 2013-09-08
      相关资源
      最近更新 更多