Google语音转文字项目中StringToNative转换代码功能咨询
C++/CLI互操作转换类功能说明
这段是C++/CLI环境下专门做托管/原生内存边界转换的工具类,这类代码是混合托管+原生C开发场景下的标配,对接Google Speech to Text API时用到它,核心原因是项目同时使用了.NET托管逻辑和C原生模块,两边内存模型不兼容,无法直接跨边界传参。
相关代码如下:
ref class Converters { public: static size_t ConvertStringToNative(System::String^ string, wchar_t* native, size_t length) { size_t sizeInChar = string->Length; if (native == nullptr || sizeInChar > length) { return sizeInChar; } else { pin_ptr<const wchar_t> wch = PtrToStringChars(string); memcpy_s(native, length * sizeof(wchar_t), wch, sizeInChar * sizeof(wchar_t)); return sizeInChar; } } static array<System::Byte>^ ConvertArrayToManaged(void* value, size_t length) { auto bytes = gcnew array<System::Byte>(length); Marshal::Copy((System::IntPtr)value, bytes, 0, length); return bytes; } };
两个方法的具体逻辑
ConvertStringToNative
作用是把.NET托管堆上的System::String类型转换成C++原生可直接访问的wchar_t*宽字符数组。
执行逻辑:- 先读取托管字符串的字符长度,作为存储该字符串需要的最小缓冲区长度
- 做入参校验:如果传入的原生缓冲区指针为空,或者缓冲区长度不足以存下整个字符串,直接返回需要的字符长度,方便调用方提前分配足够大的内存
- 校验通过后,用
pin_ptr把托管字符串所在的内存临时锁定——.NET GC会在运行时移动托管堆上的对象压缩内存,如果不锁定,拷贝过程中字符串地址变更会导致内存访问错误,锁定后可以拿到托管字符串内部实际存储的宽字符数组指针 - 用安全内存拷贝函数
memcpy_s,把托管字符串的内容完整复制到传入的原生缓冲区里,最后返回实际拷贝的字符数
ConvertArrayToManaged
作用是把C++原生内存里的连续字节数据,转换成.NET可直接使用的托管字节数组,一般用来转换语音采集拿到的PCM原始音频数据。
执行逻辑:- 在托管堆上分配和传入长度一致的
System::Byte数组 - 调用
Marshal::Copy把原生内存指针指向的字节数据,整块拷贝到刚分配的托管数组中 - 返回生成的托管数组,上层.NET逻辑(比如发gRPC请求给Google STT服务的客户端)可以直接用这个数组传参
- 在托管堆上分配和传入长度一致的
为什么必须做StringToNative转换
C++/CLI项目里存在两套完全隔离的内存管理体系,不能直接跨边界传指针:
- 托管内存:由.NET CLR垃圾回收器统一管理,所有带
^标记的类型(比如System::String^、托管数组)都存储在这里,内存地址会在GC运行时被移动、回收,原生C++代码拿到这类指针后,随时可能因为GC操作变成野指针,读不到正确数据- 原生内存:通过
malloc/new或者栈分配出来的内存,地址固定,由开发者手动管理生命周期,是标准C/C接口识别的内存格式
对接Google Speech to Text时,通常会同时用到原生C写的音频采集模块、官方C++版本SDK,以及上层.NET写的业务逻辑/请求封装:
- 当需要把语言代码、模型参数这类字符串传给原生C++接口时,原生接口只认
wchar_t*类型的原生字符串,不识别托管的System::String^,必须把内容拷贝到固定地址的原生内存里才能安全传参 - Windows平台下.NET的
System::String内部本身就是用UTF-16编码的wchar_t数组存储,所以这段代码直接做内存拷贝即可,不需要额外转编码,执行效率很高
内容的提问来源于stack exchange,提问作者rium
相关产品推荐
相关产品推荐

