bigywater.tech
Java · 305

Linker:Java 如何描述 native 函数签名

Linker 怎么描述 C 函数的签名?结构体、变参、errno 各自要怎么写?写错了会怎样?上行调用里抛异常又会怎样?这篇用真实的 C 库逐个运行。

乱码
变参函数不声明 firstVariadicArg 时 snprintf 的输出(本机 arm64)
4.35 → 3.17 ns
getpid 普通下行调用与 critical(false) 调用的耗时
退出码 1
上行调用里抛出异常时 JVM 的反应

结构体按值

实测 · 本机执行输出
  1 struct{double,double}(16 字节)按值传入、按值返回:mid((1,2),(3,8)) = (2.0, 5.0);descriptor 的方法类型:(SegmentAllocator,MemorySegment,MemorySegment)MemorySegment
  2 struct{int,int}(8 字节)按值传入:pair_sum = 7009(期望 7*1000+9 = 7009)
  3 struct{long×4}(32 字节)按值返回:big_make(5) = (5, 10, 15, 20)
    big_sum(刚才返回的结构体)= 50(期望 5+10+15+20 = 50)

变参函数

实测 · 本机执行输出
  4 snprintf 变参(firstVariadicArg(3)):返回 24,内容 "42-abc-3.14-123456789012"
    不声明 firstVariadicArg(按普通函数调用):返回 31,内容 "608294592-h�-0.00-4681796456"
    firstVariadicArg(9)(超出参数个数):IllegalArgumentException: Index '9' not in bounds for descriptor: (a8j8a8i4)i4
    变参里用 JAVA_BYTE(C 会提升为 int):IllegalArgumentException: Invalid variadic argument layout: b1

捕获 errno

实测 · 本机执行输出
  5 open("/definitely/not/here") 返回 -1,捕获的 errno = 2,strerror = "No such file or directory";捕获布局 [i4(errno)]
    Linker.Option.captureStateLayout() 在本平台包含的成员:[i4(errno)]
    captureCallState("nonexistent"):IllegalArgumentException: Unknown name: nonexistent, must be one of: [errno]

critical 调用

实测 · 本机执行输出
  6 getpid:普通下行调用 4.35 ns/次;Linker.Option.critical(false) 3.17 ns/次(各 2000 万次,取第 4、5 轮较小值)

上行调用

实测 · 本机执行输出
  7 C 回调 Java 函数 10 次:callback_sum = 90(期望 0+2+…+18 = 90),Java 方法被调用 10 次;stub 地址非空:true
    上行调用的方法类型与 descriptor 不匹配(返回 long 对 int):IllegalArgumentException: Wrong method handle type: (int)int
    invokeExact 参数类型写错(long 对 int):WrongMethodTypeException: handle's method type (MemorySegment,int)int but found (MemorySegment,long)void

上行调用里抛异常

实测 · 本机执行输出
  java.lang.IllegalStateException: 上行调用里抛出的异常
  	at Main.boom(Main.java:8)
  	at Main.main(Main.java:57)
  Unrecoverable uncaught exception encountered. The VM will now exit
  (退出码 1)

分步演示

Linker 与 native 调用
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK(Temurin 17.0.20、Homebrew 21.0.12 与 27,每篇注明实际用的版本);用 javac 编译、java 直接运行,需要第三方库时用 Maven 解析依赖;计时用 System.nanoTime,数字每次运行会有小幅抖动。JDK 27,macOS arm64;C 库用 clang 编译
    • 没有验证:x86-64 与 Windows 的调用约定、不同大小结构体在寄存器与栈之间传递的细节(只验证了结果正确)、critical 的 GC 影响、JDK 21 预览版的同名 API(captureCallState 等)、Linker.Option.captureCallState 在 Windows 上的更多成员
    京ICP备2026067502号-1京公网安备11010502063487号