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

C#调用C++编译的DLL时整数方法正常但字符串返回乱码如何解决?

问题根因

字符串乱码问题本质是跨语言交互的类型不兼容,核心有两个问题:

  • C++ 标准库的 std::string 是包含数据指针、长度、容量等成员的复合结构体,和 C# 期望的以\0结尾的C风格字符串指针完全不匹配,C# 会把结构体的内存内容当成指针解析,自然读到乱码。
  • std::string 是C++函数内的临时对象,函数执行结束后就会被析构,对应的内存被回收,C#拿到的是野指针,所以每次运行的乱码内容都不一样。
    整数返回正常是因为int是基础值类型,跨平台跨语言的内存布局一致,不存在解析和内存管理问题。
解决方案

方案一:简易适配(适合返回固定字符串场景)

1. 修改C++端代码

只需要把返回值从std::string改为C风格的const char*,返回静态存储的字符串字面值即可:

// test.h 修改
#include <iostream>
using namespace std;

#define EXPORT_API __declspec(dllexport)

extern "C" EXPORT_API const char* SayHi();
extern "C" EXPORT_API int CallNumber();
// test.cpp 修改
#include <iostream>
#include "test.h"
using namespace std;

const char* SayHi(){
    return "hi"; // 字符串字面值存储在静态常量区,不会被释放
}

int CallNumber(){
    return 911;
}

还是用原命令编译生成DLL:
g++ -shared -o test.dll test.cpp

2. 修改C#端代码

需要在DllImport特性中指定字符集,并且告知.NET不要自动释放返回的字符串内存(这部分是C++的静态内存,不需要C#回收):

using System;
using System.Runtime.InteropServices;

namespace Test.Main
{
  class Program
  {
    [DllImport(@"test.dll", CharSet = CharSet.Ansi)]
    [return: MarshalAs(UnmanagedType.LPStr)]
    public static extern string SayHi();

    [DllImport(@"test.dll")]
    public static extern int CallNumber();

    static void Main(string[] args)
    {
      Console.WriteLine(SayHi());
      Console.WriteLine(CallNumber());
      Console.ReadKey();
    }
  }
}

方案二:通用安全方案(适合返回动态字符串场景)

如果返回的字符串是动态生成的(比如运行时拼接的内容),静态字符串无法满足需求,推荐用C#分配缓冲区,C++写入内容的方式,内存完全由C#管理,不存在泄漏风险:

1. 修改C++端代码

// test.h 修改
extern "C" EXPORT_API void SayHi(char* buffer, int bufferLen);
// test.cpp 修改
void SayHi(char* buffer, int bufferLen){
    const char* res = "hi";
    strncpy(buffer, res, bufferLen - 1); // 留一个位置给结束符\0
    buffer[bufferLen - 1] = '\0';
}

2. 修改C#端代码

[DllImport(@"test.dll", CharSet = CharSet.Ansi)]
public static extern void SayHi(StringBuilder buffer, int bufferLen);

// 调用时先分配足够大的缓冲区
static void Main(string[] args)
{
    StringBuilder sb = new StringBuilder(256); // 分配256字节的缓冲区
    SayHi(sb, sb.Capacity);
    Console.WriteLine(sb.ToString());
    Console.WriteLine(CallNumber());
    Console.ReadKey();
}
注意事项
  • 不推荐在C++中用new或者malloc分配字符串内存返回给C#,如果必须这么做,要用CoTaskMemAlloc分配内存,C#默认会用CoTaskMemFree释放返回的字符串内存,否则会出现内存泄漏。
  • 如果需要返回中文等非ASCII字符,建议统一用UTF8编码,两边指定对应的字符集即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 04:24:04