.Net 字符集与编解码

0 .NET 字符集编解码

.Net 内部使用的字符集是Unicode,如果需要编码为其他诸如GBK、UTF8编码,可以通过Encoding 类来实现。

using System.Text;void PrintBytes(byte[] bytes)
{foreach (var b in bytes){Console.Write("{0:X} ", b);}Console.WriteLine();
}Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);string str = "主账号";var gbkBytes = Encoding.GetEncoding("gbk").GetBytes(str);       //获取GBK编码
var utf8Bytes = Encoding.UTF8.GetBytes(str);                    //获取UTF8编码
var unicodeBytes = Encoding.Unicode.GetBytes(str);              //获取Unicode编码PrintBytes(gbkBytes);
PrintBytes(utf8Bytes);
PrintBytes(unicodeBytes);var gbkStr = Encoding.GetEncoding("gbk").GetString(gbkBytes);   //使用GBK解码
var utf8Str = Encoding.UTF8.GetString(utf8Bytes);               //使用UTF8解码
var unicodeStr = Encoding.Unicode.GetString(unicodeBytes);      //使用Unicode解码Console.WriteLine(gbkStr);
Console.WriteLine(utf8Str);
Console.WriteLine(unicodeStr);

输出:

D6 F7 D5 CB BA C5
E4 B8 BB E8 B4 A6 E5 8F B7
3B 4E 26 8D F7 53
主账号
主账号
主账号

在使用C++API时,当遇到字符串处理时难免会需要处理字符编码的问题。这里主要针对于使用C++ API是遇到的一些编码被封送的情况测试。

1 Windows环境下

这里首先测试了.Net 在Windows环境下运行情况下,.Net 默认使用ANSI 编解码,其中在 DllImport 中指定的 CharSet 对导出函数的直接字符串参数生效。CharSet 取值与C++ API 端接收到的字符串情况对应如下:

1.1 请求函数:C# => C++

1.1.1 测试函数字符串参数编码

输入文字:主账号

CharSetC++API端接收到的字符集输出Byte值
不设置GBKD6 F7 D5 CB BA C5 
AnsiGBKD6 F7 D5 CB BA C5 
UnicodeUnicode3B 4E 26 8D F7 53 
AutoUnicode3B 4E 26 8D F7 53 
NoneGBKD6 F7 D5 CB BA C5 

测试接口代码:

    //对这个接口分别设置为以下5种情况进行测试[DllImport(LibName, CallingConvention = CallingConvention.StdCall)]public static extern void RegisterFront(string ip, int port);[DllImport(LibName, CharSet=CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]public static extern void RegisterFront(string ip, int port);[DllImport(LibName, CharSet=CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]public static extern void RegisterFront(string ip, int port);[DllImport(LibName, CharSet=CharSet.Auto, allingConvention = CallingConvention.StdCall)]public static extern void RegisterFront(string ip, int port);[DllImport(LibName, CharSet=CharSet.None, CallingConvention = CallingConvention.StdCall)]public static extern void RegisterFront(string ip, int port);
1.1.2 测试函数结构体参数中的字符串编码

在这个 DllImport 中设置的CharSet 仅对接口函数的直接字符串类型生效。如果参数是一个对象,而对象中的字符串类型需要在定义封装对象的位置,通过StructLayout 属性的CharSet 来设置。我这里测试下来,CharSet 取值与C++ API 端接收到的字符串情况对应如下:

输入文字:主账号

CharSetC++API端接收到的字符集输出Byte值
不设置GBKD6 F7 D5 CB BA C5 
AnsiGBKD6 F7 D5 CB BA C5 
Unicodenull
Autonull
NoneGBKD6 F7 D5 CB BA C5 

跟上面类似,但是Unicode 传送的不成功,想必是类型问题,Unicode 对应C++中应该对应使用wchar* 数组。

测试接口及定义结构体的代码:

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public class StepReqAddPrimaryAccount
{[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 9)]public string? TradingDay;[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]public string? PrimaryAccountID;[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]public string? PrimaryAccountName;[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]public string? BrokerPassword;public int ChannelID;public bool IsAllowLogin;public AccountStatusType AccountStatus;[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]public string? Password;public int RiskGroupID;public int CommissionGroupID;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public class StepReqUpdatePrimaryAccount
{[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 9)]public string? TradingDay;[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]public string? PrimaryAccountID;[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]public string? PrimaryAccountName;[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]public string? BrokerPassword;public int ChannelID;public bool IsAllowLogin;public AccountStatusType AccountStatus;[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]public string? Password;public int RiskGroupID;public int CommissionGroupID;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.None)]
public class StepReqAddAccount
{[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 9)]public string? TradingDay;[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]public string? AccountID;[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]public string? AccountName;public AccountStatusType AccountStatus;[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]public string? Password;public int TradeGroupID;public int RiskGroupID;public int CommissionGroupID;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public class StepReqUpdateAccount
{[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 9)]public string? TradingDay;[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]public string? AccountID;[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]public string? AccountName;public AccountStatusType AccountStatus;[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]public string? Password;public int TradeGroupID;public int RiskGroupID;public int CommissionGroupID;
}
	[DllImport(LibName, CharSet=CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]public static extern int ReqAddPrimaryAccount(StepReqAddPrimaryAccount reqAddPrimaryAccount, int requestID);[DllImport(LibName, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]public static extern int ReqUpdatePrimaryAccount(StepReqUpdatePrimaryAccount reqUpdatePrimaryAccount, int requestID);[DllImport(LibName, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]public static extern int ReqAddAccount(StepReqAddAccount reqAddAccount, int requestID);[DllImport(LibName, CharSet = CharSet.None, CallingConvention = CallingConvention.StdCall)]public static extern int ReqUpdateAccount(StepReqUpdateAccount reqUpdateAccount, int requestID);

1.2 回调函数:C++ => C#

返回值:正确

C++中编码:GBK

CharSetC#回调函数接收到字符集解码情况
不设置GBK正确
AnsiGBK正确
Unicodenull乱码
Autonull乱码
NoneGBK正确

C++中编码:Utf8

相关测试代码:

//依次将CharSet 设置为:不设置值、Ansi、Unicode、Auto、None,进行测试
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public class StepRspInfo
{public int ErrorID;[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]public string? ErrorMsg;
}

回调委托定义:

[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void OnRspAdminUserLogin(StepRspAdminUserLogin? rspAdminUserLogin, StepRspInfo? rspInfo, int requestID, bool isLast);

2 Linux环境下

2.1 请求函数: C# => C++

2.1.1 测试函数字符串参数编码

 输入文字:主账号

CharSetC++API端接收到的字符集输出Byte值
不设置UTF8E4 B8 BB E8 B4 A6 E5 8F B7
AnsiUTF8E4 B8 BB E8 B4 A6 E5 8F B7
UnicodeUnicode3B 4E 26 8D F7 53
AutoUTF8E4 B8 BB E8 B4 A6 E5 8F B7
NoneUTF8E4 B8 BB E8 B4 A6 E5 8F B7

测试接口代码:

    //对这个接口分别设置为以下5种情况进行测试[DllImport(LibName, CallingConvention = CallingConvention.StdCall)]public static extern void RegisterFront(string ip, int port);[DllImport(LibName, CharSet=CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]public static extern void RegisterFront(string ip, int port);[DllImport(LibName, CharSet=CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]public static extern void RegisterFront(string ip, int port);[DllImport(LibName, CharSet=CharSet.Auto, allingConvention = CallingConvention.StdCall)]public static extern void RegisterFront(string ip, int port);[DllImport(LibName, CharSet=CharSet.None, CallingConvention = CallingConvention.StdCall)]public static extern void RegisterFront(string ip, int port);
2.1.2 测试函数结构体参数中的字符串编码

通过StructLayout 属性的CharSet 来设置结构体中的字符串编码,CharSet 取值与C++ API 端接收到的字符串情况对应如下:

输入文字:主账号

CharSetC++API端接收到的字符集输出Byte值
不设置UTF8E4 B8 BB E8 B4 A6 E5 8F B7
AnsiUTF8E4 B8 BB E8 B4 A6 E5 8F B7
Unicodenull
AutoUTF8E4 B8 BB E8 B4 A6 E5 8F B7
NoneUTF8E4 B8 BB E8 B4 A6 E5 8F B7

跟上面类似,但是Unicode 传送的不成功,想必是类型问题,Unicode 对应C++中应该对应使用wchar* 数组。

测试接口及定义结构体的代码:

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public class StepReqAddPrimaryAccount
{[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 9)]public string? TradingDay;[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]public string? PrimaryAccountID;[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]public string? PrimaryAccountName;[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]public string? BrokerPassword;public int ChannelID;public bool IsAllowLogin;public AccountStatusType AccountStatus;[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]public string? Password;public int RiskGroupID;public int CommissionGroupID;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public class StepReqUpdatePrimaryAccount
{[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 9)]public string? TradingDay;[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]public string? PrimaryAccountID;[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]public string? PrimaryAccountName;[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]public string? BrokerPassword;public int ChannelID;public bool IsAllowLogin;public AccountStatusType AccountStatus;[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]public string? Password;public int RiskGroupID;public int CommissionGroupID;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.None)]
public class StepReqAddAccount
{[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 9)]public string? TradingDay;[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]public string? AccountID;[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]public string? AccountName;public AccountStatusType AccountStatus;[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]public string? Password;public int TradeGroupID;public int RiskGroupID;public int CommissionGroupID;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public class StepReqUpdateAccount
{[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 9)]public string? TradingDay;[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]public string? AccountID;[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]public string? AccountName;public AccountStatusType AccountStatus;[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]public string? Password;public int TradeGroupID;public int RiskGroupID;public int CommissionGroupID;
}
	[DllImport(LibName, CharSet=CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]public static extern int ReqAddPrimaryAccount(StepReqAddPrimaryAccount reqAddPrimaryAccount, int requestID);[DllImport(LibName, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]public static extern int ReqUpdatePrimaryAccount(StepReqUpdatePrimaryAccount reqUpdatePrimaryAccount, int requestID);[DllImport(LibName, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]public static extern int ReqAddAccount(StepReqAddAccount reqAddAccount, int requestID);[DllImport(LibName, CharSet = CharSet.None, CallingConvention = CallingConvention.StdCall)]public static extern int ReqUpdateAccount(StepReqUpdateAccount reqUpdateAccount, int requestID);

 2.2 回调函数: C++ => C#

 返回值:正确

C++中编码:GBK

CharSetC#解码情况
不设置乱码
Ansi乱码
Unicode乱码
Auto乱码
None乱码

C++中编码:Utf8

相关测试代码:

//依次将CharSet 设置为:不设置值、Ansi、Unicode、Auto、None,进行测试
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public class StepRspInfo
{public int ErrorID;[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]public string? ErrorMsg;
}

回调委托定义:

[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void OnRspAdminUserLogin(StepRspAdminUserLogin? rspAdminUserLogin, StepRspInfo? rspInfo, int requestID, bool isLast);

3 结论

当在与C++ API 交互时,如果在windows平台运行,建议使用GBK编码进行通信;而在Linux平台运行的话,建议使用 UTF8编码进行通信。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/207257.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

无mac电脑生成uniapp云打包私钥证书的攻略

uniapp顾名思义是一个跨平台的开发工具,大部分uniapp的开发者,其实并没有mac电脑来开发,但是生成ios的证书,官网的教程却是需要mac电脑的,那么有没有办法无需mac电脑即可生成uniapp云打包的私钥证书呢? 下…

【计算机网络】14、DHCP

文章目录 一、概述1.1 好处 二、概念2.1 分配 IP2.2 控制租赁时间2.3 DHCP 的其他网络功能2.4 IP地址范围和用户类别2.5 安全 三、DHCP 消息3.1 DHCP discover message3.2 DHCP offers a message 如果没有 DHCP,IT管理者必须手动选出可用的 ip,这太耗时了…

和鲸科技与国科环宇建立战略合作伙伴关系,以软硬件一体化解决方案促进科技创新

近日,在国科环宇土星云算力服务器产品发布会暨合作伙伴年度会上,和鲸科技与国科环宇正式完成战略伙伴签约仪式,宣布达成战略合作伙伴关系。未来,双方将深化合作,充分发挥在产品和市场方面的互补优势,为企事…

什么是工业物联网(IOT)?这样的IOT平台你需要吗?——青创智通

物联网(IOT)是指在互联网上为传输和共享数据而嵌入传感器和软件的互联设备的广泛性网络。这允许将从物理对象收集的信息(数据)存储在专用服务器或云中。通过分析这些积累的信息,通过提供最优的设备控制和方法,可以实现一个更安全、更方便的社会。在智能家…

【NodeJS】 API Key 实现 短信验证码功能

这里使用的平台是 短信宝整体来讲还是挺麻烦的平台必须企业才行,个人是无法使用该平台的 平台必须完成 身份信息认证 和 企业认证 这里就需要 “营业执照”了 ,没有 “营业执照” 的朋友还是后退一步吧 后端我用的是NodeJS ,使用第三方库 ro…

【办公软件】电脑开机密码忘记了如何重置?

这个案例是家人的电脑,已经使用多年,又是有小孩操作过的,所以电脑密码根本不记得是什么了?那难道这台电脑就废了吗?需要重新装机吗?那里面的资料不是没有了? 为了解决以上问题,一般…

【云原生系列】Kubernetes知识点

目录 概念 基础架构 单master节点 多master节点 组件 Master节点核心组件 其他组件 请求发送流程 插件 核心资源 调度资源 Pod 创建pod组件间调用流程 pod生命周期: 初始化容器 镜像拉取策略 重启策略 钩子函数 探针 探针的实现方式 DownwardAP…

Git的介绍和下载安装

Git的介绍和下载安装 概述 Git是一个分布式版本控制工具, 通常用来管理项目中的源代码文件(Java类、xml文件、html页面等)进行管理,在软件开发过程中被广泛使用 Git可以记录文件修改的历史记录并形成备份从而实现代码回溯, 版本切换, 多人协作, 远程备份的功能Git具有廉价的…

FPGA falsh相关知识总结

1.存储容量是128M/8 Mb16MB 2.有256个sector扇区*每个扇区64KB16MB 3.一页256Byte 4.页编程地址0256 5:在调试SPI时序的时候一定注意,miso和mosi两个管脚只要没发送数据就一定要悬空(处于高组态),不然指令会通过两…

年终好价节入手什么数码合适?盘点23年度值得入手的数码好物

各位科技控和数码迷!时间过得飞快,一眨眼2023年就要过去了,说到年底,当然少不了年终好价节啦!这时候正是更新你的数码装备、升级生活品质的绝佳时机。别管你是不是科技控,工作狂还是生活追求者,…

JavaWeb服务器详解和后端分层解耦

JavaWeb HTTP协议请求数据格式响应数据格式协议解析 Web服务器请求响应请求参数的接收响应 分层解耦IOC&DI入门IOC详解 HTTP协议 超文本传输协议,规定了浏览器和服务器之间数据传输的规则 特点: 基于TCP协议:面向连接,安全 …

npm WARN npm npm does not support Node.js v13.9.0

Microsoft Windows [版本 10.0.19045.2965] (c) Microsoft Corporation。保留所有权利。C:\Users\Administrator>node -v v13.9.0C:\Users\Administrator>npm -v npm WARN npm npm does not support Node.js v13.9.0 npm WARN npm You should probably upgrade to a newe…

正则表达式回溯陷阱

一、匹配场景 判断一个句子是不是正规英文句子 text "I am a student" 一个正常的英文句子如上,英文单词 空格隔开 英文单词 多个英文字符 [a-zA-Z] 空格用 \s 表示 那么一个句子就是单词 空格(一个或者多个,最后那个单词…

力扣:1419. 数青蛙

题目&#xff1a; 代码&#xff1a; class Solution { public:int minNumberOfFrogs(string croakOfFrogs){string s "croak";int ns.size();//首先创建一个哈希表来标明每个元素出现的次数&#xff01;vector<int>hash(n); //不用真的创建一个hash表用一个数…

40.0/jdbc/Java数据连接/jar包运用增删改

目录 40.1. 回顾 40.2. 正文 40.1 为什么需要jdbc 40.2 如何连接mysql数据库 40 .3 jdbc容易出现的错误 40.4 完成删除 40.5 完成修改 40.1. 回顾 1. 自联查询: 自己连接自己的表。注意:一定要为表起别名。 2. 嵌套查询: 把一个查询的结果作为另一个查询的条件值。 3. 组…

高效率:使用DBeaver连接spark-sql

提高运行效率一般采取底层使用spark引擎替换成hive引擎的方式提高效率&#xff0c;但替换引擎配置较为复杂考虑到兼容版本且容易出错&#xff0c;所以本篇将介绍使用DBeaver直接连接spark-sql快速操作hive数据库。 在spark目录下运行以下命令&#xff0c;创建一个SparkThirdSe…

计算机网络:网络层

0 本节主要内容 问题描述 解决思路 1 问题描述 两大问题&#xff08;重点&#xff0c;也是难点&#xff09;&#xff1a; 地址管理&#xff1b;路由选择。 1.1 子问题1&#xff1a;地址管理 网络上的这些主机和节点都需要使用一种规则来区分&#xff0c;就相当于是一种身…

数据可视化:用图表和图形展示数据

写在开头 在当今信息爆炸的时代,海量的数据如同一座沉默的宝库,等待着我们挖掘和理解。然而,这些庞大的数据集本身可能令人望而生畏。在这个时候,数据可视化成为了解数据、发现模式和传达信息的强大工具。本篇博客将带领你探索数据可视化的奇妙世界,学习如何在python中使…

【Java程序员面试专栏 专业技能篇 】Java SE核心面试指引(四):Java新特性

关于Java SE部分的核心知识进行一网打尽,包括四部分:基础知识考察、面向对象思想、核心机制策略、Java新特性,通过一篇文章串联面试重点,并且帮助加强日常基础知识的理解,全局思维导图如下所示 本篇Blog为第四部分:Java新特性,子节点表示追问或同级提问 Java8新特性…

第一百八十五回 如何禁止页面跟随手机自动旋转

文章目录 1. 概念介绍2. 使用方法2.1 全面禁止2.2 局部禁止3. 示例代码4. 内容总结我们在上一章回中介绍了"如何自定义Radio组件"相关的内容,本章回中将介绍 如何禁止页面随手机自动旋转.闲话休提,让我们一起Talk Flutter吧。 1. 概念介绍 在手机默认设置下,手机…