C#向C++封送UTF8中文字符串数组时的编码异常问题
解决C#封送string[]到C++时UTF-8字节符号扩展问题
问题本质
- .NET默认使用系统ANSI编码(
Encoding.Default)封送string到C++的char*,而非UTF-8,导致中文路径编码错误。 - 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
相关产品推荐
相关产品推荐

