如何在 C# 中使用 Swig 包装 UTF-8 编码C++ std::strings
How to wrap UTF-8 encoded C++ std::strings with Swig in C#?
我的问题与这个问题几乎相同,只是链接的问题处理char*,而我在代码中使用std::string。就像链接的问题一样,我也使用 C# 作为我的目标语言。
我有一个用C++写的类:
class MyClass
{
public:
const std::string get_value() const; // returns utf8-string
void set_value(const std::string &value); // sets utf8-string
private:
// ...
};
SWIG 在 C# 中包装了这个 get,如下所示:
public class MyClass
{
public string get_value();
public void set_value(string value);
}
SWIG 为我做了一切,除了在调用 MyClass 期间它不会进行 utf8 到 utf16 字符串的转换。如果字符串可以用 ASCII 表示,我的字符串就可以通过,但是如果我尝试通过"set_value"和"get_value"往返传递带有非 ASCII 字符的字符串,我最终会得到难以理解的字符。
如何使 SWIG 在 C# 中包装 UTF-8 编码C++字符串? 注意我使用的是 std::string,而不是 std::wstring,也不是 char*。
SWIG sourceforge 站点上有一个部分解决方案,但它处理的是 char* 而不是 std::string,并且它使用(可配置的)固定长度缓冲区。
在链接的代码项目文章中David Jeske的帮助下(阅读:天才!),我终于能够回答这个问题。
C# 库中需要此类(来自 David Jeske 的代码)。
public class UTF8Marshaler : ICustomMarshaler {
static UTF8Marshaler static_instance;
public IntPtr MarshalManagedToNative(object managedObj) {
if (managedObj == null)
return IntPtr.Zero;
if (!(managedObj is string))
throw new MarshalDirectiveException(
"UTF8Marshaler must be used on a string.");
// not null terminated
byte[] strbuf = Encoding.UTF8.GetBytes((string)managedObj);
IntPtr buffer = Marshal.AllocHGlobal(strbuf.Length + 1);
Marshal.Copy(strbuf, 0, buffer, strbuf.Length);
// write the terminating null
Marshal.WriteByte(buffer + strbuf.Length, 0);
return buffer;
}
public unsafe object MarshalNativeToManaged(IntPtr pNativeData) {
byte* walk = (byte*)pNativeData;
// find the end of the string
while (*walk != 0) {
walk++;
}
int length = (int)(walk - (byte*)pNativeData);
// should not be null terminated
byte[] strbuf = new byte[length];
// skip the trailing null
Marshal.Copy((IntPtr)pNativeData, strbuf, 0, length);
string data = Encoding.UTF8.GetString(strbuf);
return data;
}
public void CleanUpNativeData(IntPtr pNativeData) {
Marshal.FreeHGlobal(pNativeData);
}
public void CleanUpManagedData(object managedObj) {
}
public int GetNativeDataSize() {
return -1;
}
public static ICustomMarshaler GetInstance(string cookie) {
if (static_instance == null) {
return static_instance = new UTF8Marshaler();
}
return static_instance;
}
}
然后,在 Swig 的"std_string.i"中,在第 24 行替换这一行:
%typemap(imtype) string "string"
用这一行:
%typemap(imtype, inattributes="[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]", outattributes="[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]") string "string"
在第 61 行,替换此行:
%typemap(imtype) const string & "string"
用这一行:
%typemap(imtype, inattributes="[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]", outattributes="[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]") string & "string"
你瞧,一切正常。阅读链接的文章,以很好地理解其工作原理。
相关文章:
- 如何在CPP的给定目录中列出UTF编码的文件名?
- 如何使用 C++将 ISO-2022-KR 编码转换为 UTF-8 编码?
- 将C++ std::string 转换为 UTF-16-LE 编码的字符串
- PostgreSQL C++ libpq 编码 UTF-8 问题
- 如何使用utf-8编码在Qt5 WebEngineView中加载HTML页面?
- 如何在 c++ 中读取用 utf-8 编码的 java unicode 字节字符串
- 如何从Little Endian UTF-16编码字节中获取C++std::string
- 如何C++ WCOUT UTF-16 编码的字符数组?
- QT 无法识别 UTF-8 编码,适用于其他所有位置
- 如何在没有wchar_t的情况下在 c++ 中解码/编码 UTF-8 字符
- UTF-16LE 编码问题与 Qt 文本编辑器用 C++ 编写
- 有关读取 UTF-8 编码文本时 Ifstream get() 方法行为的说明 (C++)
- 如何将UTF-8字符串转换为流的编码
- C 14:UTF-8/UTF-16与本机字符编码之间的转换
- 如何在Qt中通过QTcpSocket发送UTF-8编码的字符串
- 从键盘读取 UTF-8 编码的字符
- Windows的unicode数据类型使用什么unicode编码(UTF-8、UTF-16等)
- 如何从文件中写入的UTF-8编码的URDU字符串中获取单个字符
- C++ 字符串 UTF-8 编码
- C++ncurses编码(UTF-8)问题