You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从C#调用Kotlin/Native生成的原生C库中的函数?

如何从C#调用Kotlin/Native生成的C API

我来帮你一步步实现从C#调用这个Kotlin/Native导出的C库,核心是利用.NET的**P/Invoke(平台调用)**特性来对接原生函数,下面是具体的实现细节:

1. 定义C#端的类型映射

首先要把C API里的结构体、类型和函数指针,对应转换成C#的托管类型:

using System;
using System.Runtime.InteropServices;

// 对应C里的bar_KNativePtr
using bar_KNativePtr = IntPtr;

// 对应C里的bar_KBoolean(Kotlin/Native通常用uint8_t,这里根据需求选bool或byte)
using bar_KBoolean = bool;

// 对应C里的bar_KType(无需直接操作,用IntPtr占位即可)
using bar_KType = IntPtr;

// 定义服务函数的委托
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void DisposeStablePointerDelegate(bar_KNativePtr ptr);

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void DisposeStringDelegate(IntPtr str);

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate bar_KBoolean IsInstanceDelegate(bar_KNativePtr reference, bar_KType type);

// 定义用户函数里的root嵌套结构体
[StructLayout(LayoutKind.Sequential)]
public struct RootFunctions
{
    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate void FooDelegate(IntPtr str);

    public FooDelegate foo;
}

// 定义kotlin层级的嵌套结构体
[StructLayout(LayoutKind.Sequential)]
public struct KotlinFunctions
{
    public RootFunctions root;
}

// 定义最外层的导出符号结构体
[StructLayout(LayoutKind.Sequential)]
public struct bar_ExportedSymbols
{
    // 服务函数集合
    public DisposeStablePointerDelegate DisposeStablePointer;
    public DisposeStringDelegate DisposeString;
    public IsInstanceDelegate IsInstance;

    // 用户自定义函数集合
    public KotlinFunctions kotlin;
}

2. 声明原生库的导出函数

用[DllImport]特性声明获取导出符号的bar_symbols函数:

public static class BarNativeLibrary
{
    // 替换为你的原生库文件名(Windows是bar.dll,Linux是libbar.so,macOS是libbar.dylib)
    private const string LibraryName = "bar";

    [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
    public static extern IntPtr bar_symbols();
}

3. 在C#中调用原生函数

现在就可以获取导出的符号结构体,然后调用目标函数了,内存管理是这里的关键:

class Program
{
    static void Main(string[] args)
    {
        // 获取导出符号的指针,转换为C#托管结构体
        IntPtr symbolsPtr = BarNativeLibrary.bar_symbols();
        bar_ExportedSymbols symbols = Marshal.PtrToStructure<bar_ExportedSymbols>(symbolsPtr);

        // 准备要传递的字符串:转换为原生ANSI编码的内存块
        string message = "Hello from C#!";
        IntPtr nativeStr = Marshal.StringToHGlobalAnsi(message);

        try
        {
            // 调用Kotlin导出的foo函数
            symbols.kotlin.root.foo(nativeStr);
        }
        finally
        {
            // 释放C#分配的原生字符串(如果是Kotlin返回的字符串,必须用symbols.DisposeString释放)
            Marshal.FreeHGlobal(nativeStr);
        }

        // 注:导出符号结构体是原生库的全局对象,无需手动释放
    }
}

关键注意事项

  • 调用约定:必须指定CallingConvention.Cdecl,因为Kotlin/Native生成的C API默认使用Cdecl调用约定,不匹配会导致程序崩溃。
  • 内存管理:
    • C#主动分配的原生内存(比如Marshal.StringToHGlobalAnsi创建的),要用Marshal.FreeHGlobal释放。
    • 由Kotlin/Native返回的字符串或稳定指针,必须用结构体里的DisposeString或DisposeStablePointer方法释放,避免内存泄漏。
  • 类型匹配:如果bar_KBoolean在C中是uint8_t,可以用C#的byte类型对应,避免跨平台下bool类型的兼容性问题。

内容的提问来源于stack exchange,提问作者Xaero Degreaz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 12:14:19