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

Xamarin Android:C#向C++封送Unicode字符串仅显首字符的解决方法

解决Xamarin Android调用C++库时Unicode字符串仅显示首字符的问题

这个问题的核心原因是Android NDK中wchar_t的编码与C#封送的Unicode字符串不匹配,咱们一步步拆解解决:

问题根源

在Android的NDK环境中,wchar_t是4字节的UTF-32编码;而C#的CharSet.Unicode和[MarshalAs(UnmanagedType.LPWStr)]会将.NET的UTF-16字符串(每个字符2字节)转换为2字节的宽字符数组传递给原生库。

当你在C中用__android_log_print的%ls格式符打印wchar_t*时,它期望每个字符占4字节,但收到的是2字节的UTF-16数据——比如字符'1'的UTF-16表示是0x31 0x00,第二个字节的0x00会被C当成字符串的终止符,所以只显示第一个字符。

解决方案(推荐方案):C++端使用char16_t匹配C#的UTF-16

char16_t是C++11标准定义的、专门用于UTF-16编码的字符类型,正好和C#封送的LPWStr(UTF-16)匹配。修改代码如下:

1. 修改C++原生库代码

#include <android/log.h>
#include <string>
#include <codecvt> // 用于UTF-16到UTF-8的转换

extern "C" void logANSI(const char* data) {
    __android_log_print(ANDROID_LOG_INFO, "StringMarshaling", "ANSI data: %s", data);
}

extern "C" void logUnicode(const char16_t* data) {
    // 将UTF-16字符串转换为UTF-8(Android日志默认支持UTF-8)
    std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> converter;
    std::string utf8_str = converter.to_bytes(data);
    
    __android_log_print(ANDROID_LOG_INFO, "StringMarshaling", "Unicode data: %s", utf8_str.c_str());
}

注意:如果你的NDK工具链不支持std::codecvt,可以改用Android原生的utf16_to_utf8函数(需包含android/utf.h头文件),或者手动实现简单的UTF-16到UTF-8转换。

2. 保持C#端的DllImport声明不变

原有的C#声明已经是正确的UTF-16封送配置,无需修改:

[DllImport("StringMarshaling", EntryPoint = "logANSI", SetLastError = true, CharSet = CharSet.Ansi, ThrowOnUnmappableChar = true)]
public static extern void LogANSI([MarshalAs(UnmanagedType.LPStr)] string data);

[DllImport("StringMarshaling", EntryPoint = "logUnicode", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern void LogUnicode([MarshalAs(UnmanagedType.LPWStr)] string data);

备选方案:C#端封送为UTF-32匹配C++的wchar_t

如果不想修改C代码,可以让C#将字符串转换为UTF-32(4字节宽字符)后传递,对应C的wchar_t*:

修改C#的DllImport声明

[DllImport("StringMarshaling", EntryPoint = "logUnicode", SetLastError = true)]
public static extern void LogUnicode([MarshalAs(UnmanagedType.LPUTF32Str)] string data);

此方案需要.NET Framework 4.6+(Xamarin Android通常支持),但因为要做UTF-16到UTF-32的转换,效率略低于第一种方案,仅推荐在无法修改C++代码时使用。

验证结果

修改后再次调用StringMarshaling.LogUnicode("12345"),日志应该会完整输出Unicode data: 12345。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 06:22:27