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

C#调用C++ DLL导出的std::string返回值函数无输出如何解决

C# P/Invoke调用C++ DLL返回字符串失败的解决方法

核心问题原因

  • C++的std::string是标准库专属自定义类型,不属于C语言兼容的原生互操作类型,C#的P/Invoke封送器无法识别其内存布局,无法正确解析返回值。
  • std::string的内存由C++标准库管理,直接跨语言返回会导致内存所有权混乱,轻则无法读取内容,重则触发内存泄漏、程序崩溃。

修复方案

方案1:返回C风格常量字符串(适合固定内容的返回值)

修改后C++导出代码

extern "C"
{
    __declspec(dllexport) int SM_Interop_API_Add(int a, int b)
    {
        return a + b;
    }

    // 返回值改为C兼容的const char*,字符串常量存储在全局常量区,生命周期随进程
    __declspec(dllexport) const char* SM_Interop_API_getLanguage()
    {
        return "This is Test String";
    }
}

修改后C#调用代码

class Program
{
    [DllImport(@"CPPSample.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SM_Interop_API_Add")]
    public static extern int SM_Interop_API_Add(int a, int b);

    // 返回值改为IntPtr接收,避免C#默认尝试释放常量区内存
    [DllImport(@"CPPSample.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SM_Interop_API_getLanguage")]
    public static extern IntPtr SM_Interop_API_getLanguage();

    static void Main(string[] args)
    {
        Console.WriteLine("Hello World!");
        int sum = SM_Interop_API_Add(10, 10);
        Console.WriteLine($"Result: {sum}");
        // 手动将指针转成ANSI字符串
        IntPtr strPtr = SM_Interop_API_getLanguage();
        string result = Marshal.PtrToStringAnsi(strPtr);
        Console.WriteLine($"Sm Language: {result}");
        Console.WriteLine("----EOP----");
    }
}

方案2:缓冲区传递(适合动态生成的字符串,无内存泄漏风险)

该方案由C#侧预先分配字符串缓冲区,C++直接将内容写入缓冲区,内存完全由C#管理,兼容性最好。

修改后C++导出代码

extern "C"
{
    __declspec(dllexport) int SM_Interop_API_Add(int a, int b)
    {
        return a + b;
    }

    __declspec(dllexport) void SM_Interop_API_getLanguage(char* buffer, int bufferLength)
    {
        const char* targetStr = "This is Test String";
        // 安全拷贝,避免缓冲区溢出
        strncpy_s(buffer, bufferLength, targetStr, _TRUNCATE);
    }
}

修改后C#调用代码

class Program
{
    [DllImport(@"CPPSample.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SM_Interop_API_Add")]
    public static extern int SM_Interop_API_Add(int a, int b);

    [DllImport(@"CPPSample.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint = "SM_Interop_API_getLanguage")]
    public static extern void SM_Interop_API_getLanguage(StringBuilder buffer, int bufferLength);

    static void Main(string[] args)
    {
        Console.WriteLine("Hello World!");
        int sum = SM_Interop_API_Add(10, 10);
        Console.WriteLine($"Result: {sum}");
        // 预先分配足够大的缓冲区
        StringBuilder sb = new StringBuilder(256);
        SM_Interop_API_getLanguage(sb, sb.Capacity);
        string result = sb.ToString();
        Console.WriteLine($"Sm Language: {result}");
        Console.WriteLine("----EOP----");
    }
}

注意事项

  • C/C导出函数用于跨语言互操作时,仅可使用C兼容的原生类型,禁止传入或返回std::string、std::vector等C专属类型。
  • 如果需要返回C++侧动态分配的字符串,需配套导出内存释放函数,避免内存泄漏:
    __declspec(dllexport) void SM_Interop_FreeString(char* ptr)
    {
        free(ptr);
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.09 04:54:03