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

C#向C++封送UTF8中文字符串数组时的编码异常问题

解决C#封送string[]到C++时UTF-8字节符号扩展问题

问题本质

  1. .NET默认使用系统ANSI编码(Encoding.Default)封送string到C++的char*,而非UTF-8,导致中文路径编码错误。
  2. Windows平台下C++的char默认是有符号类型,UTF-8中值大于127的字节会被解析为负数(例如228会被解释为-28,与观测到的符号化结果逻辑一致)。

解决思路

1. 显式指定C#封送编码为UTF-8

修改DllImport声明,指定字符集为UTF-8,并明确数组元素的封送类型:

[DllImport("mydll.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.UTF8)]
static extern IntPtr inputFiles(IntPtr pAlzObj, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStr)] string[] filePaths, int fileNum);

使用时直接传入原始allfiles数组即可,.NET会自动将每个字符串转换为UTF-8编码的C风格字符串,无需手动编码转换。

2. C++端改用unsigned char接收

将C++的函数参数从char**改为unsigned char**,这样接收的字节会以无符号形式解析,直接得到0-255的原始UTF-8值:

extern __declspec(dllexport) char* inputFiles(Alz* pObj, unsigned char** filePaths, int fileNum);

char* massAdd(Alz* pObj, unsigned char** filePaths, int fileNum)
{
    // 后续处理逻辑不变,内存中字节值与UTF-8原始数据一致
}

注意确保后续字符串处理函数支持unsigned char*输入,或通过reinterpret_cast<char*>(filePaths[i])类型转换兼容现有逻辑。

3. 手动封送字符串数组(完全控制)

如果上述方法无法满足需求,可以手动在C#中构建非托管的UTF-8字符串指针数组,完全控制封送过程:

[DllImport("mydll.dll", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr inputFiles(IntPtr pAlzObj, IntPtr filePaths, int fileNum);

string[] allfiles = Directory.GetFiles("myfolder", "*.jpg", SearchOption.AllDirectories);
List<IntPtr> stringPtrs = new List<IntPtr>();

// 逐个转换字符串为UTF-8并分配非托管内存
foreach (string path in allfiles)
{
    byte[] utf8Bytes = Encoding.UTF8.GetBytes(path);
    IntPtr strPtr = Marshal.AllocHGlobal(utf8Bytes.Length + 1); // 预留null终止符空间
    Marshal.Copy(utf8Bytes, 0, strPtr, utf8Bytes.Length);
    Marshal.WriteByte(strPtr, utf8Bytes.Length, 0); // 添加null终止符
    stringPtrs.Add(strPtr);
}

// 构建指针数组
IntPtr arrPtr = Marshal.AllocHGlobal(stringPtrs.Count * IntPtr.Size);
Marshal.Copy(stringPtrs.ToArray(), 0, arrPtr, stringPtrs.Count);

try
{
    IntPtr pRet = inputFiles(pObj, arrPtr, allfiles.Length);
    // 处理返回值逻辑...
}
finally
{
    // 必须释放非托管内存,避免泄漏
    foreach (IntPtr ptr in stringPtrs)
    {
        Marshal.FreeHGlobal(ptr);
    }
    Marshal.FreeHGlobal(arrPtr);
}

4. 关于系统区域设置的影响

当系统区域设置改为「Unicode UTF-8」时,Encoding.Default会自动切换为UTF-8,因此默认封送行为会符合预期。但这是系统级配置,不能依赖用户修改,必须在代码中显式指定编码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 00:35:25