我正在开发一个项目,其中C ++ std::string
通过SWIG传递给C#应用程序。
我注意到以下UTF-8字符串存储在std::string
新東府選全紀高帯商 (27 byte)
E6 96 B0 E6 9D B1 E5 BA 9C E9 81 B8 E5 85 A8 E7 B4 80 E9 AB 98 E5 B8 AF E5 95 86
转换为
新東府選全紀高帯啁E (28 byte)
E6 96 B0 E6 9D B1 E5 BA 9C E9 81 B8 E5 85 A8 E7 B4 80 E9 AB 98 E5 B8 AF E5 95 81 45
在C#方面。 (每个字节在Visual Studio调试器中验证.C ++和C#代码都是使用Visual Studio 2013编译的)
转换代码:
public class UTF8Marshaler : global::System.Runtime.InteropServices.ICustomMarshaler {
public object MarshalNativeToManaged(global::System.IntPtr pNativeData) {
if (pNativeData == global::System.IntPtr.Zero)
return null;
// find the end of the string
int offset = 0;
while(global::System.Runtime.InteropServices.Marshal.ReadByte(pNativeData, offset++) != 0)
;
byte[] strbuf = new byte[offset-1]; // offset is 29 here
// skip the trailing null
global::System.Runtime.InteropServices.Marshal.Copy((global::System.IntPtr)pNativeData, strbuf, 0, offset-1);
string data = global::System.Text.Encoding.UTF8.GetString(strbuf); // strbuf's content matches that of data
return data;
}
// Some functions are omitted
}
转换调用是MarshalNativeToManaged(std_str.c_str())
。
此行为始终可重现,并非对示例字符串唯一。如有要求,我会发布其他例子。
这个问题没有出现在我的队友的计算机上,我怀疑它与我的Windows语言环境设置有关。具体来说,我使用日语作为非Unicode程序。但是,我没有证实我的怀疑,并且区域设置的差异并不能解释为什么Marshal.ReadByte()
误读了一些字节。
我想知道为什么会这样,以及(如果可能的话)避免它的方法。
编辑:
相关的SWIG类型地图
namespace std {
class string {
%typemap(ctype) string "char *"
%typemap(imtype, inattributes="[global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]", outattributes="[return: global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]") string "string"
%typemap(cstype) string "string"
%typemap(out) string %{ $result = SWIG_csharp_string_callback($1.c_str()); %}
%typemap(csout, excode=SWIGEXCODE) string {
string ret = $imcall;$excode
return ret;
}
%typemap(csdirectorin) string "$iminput"
%typemap(directorin) string %{ $input = SWIG_csharp_string_callback($1.c_str()); %}
}
}