跨语言之间的调用,原理是什么? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容 #Wrapper { background-color: #e2e2e2; background-image: url("/static/img/shadow_light.png"), url("//cdn.v2ex.com/assets/bgs/circuit.png"); background-repeat: repeat-x, repeat-x; } #Wrapper.Night { background-color: #1f2e3d; background-image: url("/static/img/shadow.png"), url("//cdn.v2ex.com/assets/bgs/circuit_night.png"); background-repeat: repeat-x, repeat-x; background-size: 20px 20px, 162.5px 162.5px; }
James369
V2EX    程序员

跨语言之间的调用,原理是什么?

  •  
  •   James369 2020-12-01 16:10:07 +08:00 7719 次点击
    这是一个创建于 1847 天前的主题,其中的信息可能已经有所发展或是发生改变。
    比如:
    java 通过 jni 调用 c/c++模块。
    python 通过 pybind11 调用 c/c++模块。

    这是一种基于编译器 /解释器的技术,还是什么二进制原理?
    26 条回复    2020-12-02 16:17:49 +08:00
    pursuer
        1
    pursuer  
       2020-12-01 16:19:18 +08:00 via Android
    按照对应平台的 abi 调用规则去调就可以了,有些比如 lua 的 c 接口倒是平台无关的
    rb6221
        2
    rb6221  
       2020-12-01 16:27:07 +08:00
    建议百度 jni 原理
    xx6412223
        3
    xx6412223  
       2020-12-01 16:27:13 +08:00
    对 Java 来说和 c 一样,就是动态加载链接库的过程,面试的时候基本能答出来 dlopen dlsym 就给过了
    TargaryenChen
        4
    TargaryenChen  
       2020-12-01 16:40:54 +08:00
    最近正好在做一个 JSI 相关的内容,JSI 是啥? 可以看下我写的这篇文章 https://www.hellohub.cn/react-native/
    简单来说就是在 js 引擎( v8 )和 native ( c++)之间的一个封装层。
    比方说 react-native 中就有 jsi,他做的事情就是在 native 侧向 js 中注入方法,然后在 js 侧调用注入的方法并进行传参,这就实现了 js -> c++的通讯。 同理可以利用 v8 提供的方法调用你在 js 侧 global 上注册的方法并传参,这就实现了 c++ -> js 的通讯。至于传递参数的数据类型在两侧一定是有差异的,v8 提供相应的数据类型比方说 v8::String 能够将 c++侧的 std::string 和 js 侧的 string 类型相互转换。
    James369
        5
    James369  
    OP
       2020-12-01 16:42:09 +08:00
    @janus77 百度就没意思了,一起讨论才能活跃论坛,还可以撞出火花。
    zunceng
        6
    zunceng  
       2020-12-01 16:43:32 +08:00
    当然是协议啊 从 ffi 到 rpc 约定好了大家都认的协议 不就能互相调用了么
    James369/td>
        7
    James369  
    OP
       2020-12-01 17:07:54 +08:00
    @zunceng 没那么简单吧,应该分编译型语言 A 和解释型语言 B,那么有四种情况:
    A call B, B call A, A call A, B call B
    liusir
        8
    liusir  
       2020-12-01 17:08:32 +08:00
    大神们讨论,我来学习一下
    icexin
        9
    icexin  
       2020-12-01 17:55:32 +08:00   2
    拿 Python 举例吧,用一种易于理解的方式简单说一下。

    假设你想让 Python 能调用 c 标准库里面的 puts 来打印字符串,首先需要使用 c 语言编写一个 so 模块,这个模块里面有一个签名类似 PyObject* py_puts(PyObject *self, PyObject *args)这样的 c 函数。
    在这个函数内部使用 python 源代码提供的工具函数解析 args,从而获取 python 传递过来的字符串参数,转换成 c 的字符串类型 char*,再传递给 puts 来打印。然后在 python 约定的模块初始化函数里面把 py_puts 注册到 python runtime 里面,一旦这个模块被加载,之后在 python 代码里面就可以调用 py_puts 来打印字符串了。

    那你可能问 py_puts 这个 c 函数又是怎么被调用的?原理很简单,因为 cpython 的解释器是用 c 写的,当用户在脚本里面调用 py_puts 的时候,解释器通过查表得到了我们之前注册到 runtime 的函数指针,之后就是 c 函数调用 c 函数了。
    Seawalker
        10
    Seawalker  
       2020-12-01 18:03:19 +08:00 via Android
    同一进城下,都是操作内存中的指针来实现
    zunceng
        11
    zunceng  
       2020-12-01 19:06:13 +08:00
    @James369 你想的太复杂了 n 种语言 调用的放式复杂度就是 n^2 了
    实际操作大部分语言都是以 so 格式或者 在其基础上约定一种格式( jni )来调用 c 语言,能调用 c 语言后其他语言调用就简单多了, 那么前面提到的方式 就是一种协议 /约定。

    参考资料 https://en.wikipedia.org/wiki/Foreign_function_interface
    zunceng
        12
    zunceng  
       2020-12-01 19:13:59 +08:00
    @James369 更好理解 /更实用一些的跨语言调用, 用 rpc ( grpc/thirft/jsonrpc/...)来实现跨语言调用, 一组服务通过网络调用约定好的各自提供的接口。这也是一种协议 /约定
    kingfalse
        13
    kingfalse  
       2020-12-01 19:20:28 +08:00 via Android
    还记得第一次搞 jna 是为了 winring0 模拟按键去登录网银控,件做爬,虫,想想就后怕
    hhhsuan
        14
    hhhsuan  
       2020-12-01 19:22:56 +08:00
    java 和 python 解释器不都是用 C 写的吗? C 调用 C 有啥问题?
    DoctorCat
        15
    DoctorCat  
       2020-12-01 19:27:43 +08:00   1
    动态链接库具备了语言无关的这种特性。本质上是 OS 提供的机制。
    billlee
        16
    billlee  
       2020-12-01 21:35:06 +08:00
    实际上就是大家都按 C 的接口来调用
    nightwitch
        17
    nightwitch  
       2020-12-01 23:05:57 +08:00
    不同语言之间形成一些约定啊,最常见的就是约定为 C 的 ABI 。因为操作系统的 API 和库往往以 C 的 API/ABI 提供,所以一个编程语言要使用操作系统提供的功能就要实现与 C 语言的库的交互。
    Yourshell
        18
    Yourshell  
       2020-12-01 23:07:22 +08:00
    按照约定读写内存,猜的。
    icyalala
        19
    icyalala  
       2020-12-01 23:16:09 +08:00
    去 Google 搜 calling convention
    不同 CPU 架构不一样( x86 、x64 、arm ),不同语言不一样,即使同语言也有多种声明,比如 x86 的 stdcall, fastcall, cdecl.
    Jirajine
        20
    Jirajine  
       2020-12-01 23:21:53 +08:00 via Android
    调用就是 把数据传给另一个语言写的程序->执行该程序得到结果->取回该结果。
    无论是通过 abi 、rpc 还是 rest,本质上都是一回事。
    Mithril
        21
    ithril  
       2020-12-01 23:51:48 +08:00   2
    实际上你举得这些例子都是虚拟机实现的功能,JVM 去加载了 C++的 DLL/SO,然后包了一层给虚拟机内的代码用。
    其实跨语言调用还有很多种,比如 Windows 之前的 COM 这种,它的实现是系统提供的功能。
    本质上跨语言调用要解决的问题就只有两个
    1. 如何定位并调用对方的函数。
    2. 双方的数据类型要如何转换。
    你像 Java 或者 Python 调用 C++,这两个问题是虚拟机帮你解决了。Windows 的 COM 则是系统帮你解决了一部分,IDL 帮你解决了一部分,虽然这技术当年大部分也只用在 C++上,而且现在已经没人用了。
    不过更多的则是用多进程的办法,然后通过 IPC 来处理。IPC 的方法就多了去了,但是核心上解决的也就是这两个问题。
    你可以参考一下 SWIG 这个项目,它可以让各种语言去调用 C++的代码。
    MrKrabs
        22
    MrKrabs  
       2020-12-02 03:25:09 +08:00
    dlopen
    tianyamomo
        23
    tianyamomo  
       2020-12-02 08:40:13 +08:00
    搞 cef 和 qt 的 web 控件的时候都是把 c++的方法注册到 js 的执行环境里面,整个 js 环境都是 c/c++写的这应该不难,其他的都应该差不多吧
    young1lin
        24
    young1lin  
       2020-12-02 10:20:30 +08:00
    我记得 Java 调用 DLL 也是有限制的,对应的 C++ 代码必须放在 JAVA_HOME/bin 下面好像。Java 虚拟机对这个 native 函数编译的时候就开始语法解析了。
    mingl0280
        25
    mingl0280  
       2020-12-02 16:06:03 +08:00 via Android
    Linux: dlopen(), dlsym(), dlclose()
    Windows: LoadLibrary(), GetProcAddress(), FreeLibrary()
    mingl0280
        26
    mingl0280  
       2020-12-02 16:17:49 +08:00 via Android
    底层实际上是操作系统提供的一系列动态加载可执行代码的操作。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     921 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 29ms UTC 21:09 PVG 05:09 LAX 13:09 JFK 16:09
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86