.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.mfbz.cn/a/204157.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

docker-compose;私有镜像仓库harbor搭建;镜像推送到私有仓库harbor

docker-compose;私有镜像仓库harbor搭建;镜像推送到私有仓库harbor 文章目录 docker-compose;私有镜像仓库harbor搭建;镜像推送到私有仓库harbordocker-compose私有镜像仓库harbor搭建镜像推送到私有仓库harbor docker-compose D…

IC卡卡号,UID卡CUID卡物理卡号修改

普通M1卡的卡号是锁死的,不能修改,考勤工作证等使用的就是IC卡的物理卡号,读卡器读取后转换成10进制输出,出厂就固化了,因此用户拿到手的卡片卡号是不连续的,也是没有规律的,比如物理卡号8602A2…

Appium+python+unittest搭建UI自动化框架

阅读本小节,需要读者具备如下前提条件: 1. 掌握一种编程语言基础,如java、python等。 2. 掌握一种单元测试框架,如java语言的testng框架、python的unittest框架。 3. 掌握目前主流的UI测试框架,移动端APP测试框架…

【路径规划】move_base、路径规划算法、局部避障算法介绍

资料整理供个人学习使用。 文章目录 一、move_base1、move_base 包内容2、move_base 参数解析1. move_base 参数2. 全局代价地图参数3. 局部代价地图参数4. 全局规划器参数5. 局部规划器参数 二、路径规划1、Dijkstra2、最佳优先搜索3、A*4、A* 和 Dijkstra 比较 三、局部避障1…

基于SSM搭建系统

原理 SSM集成 SpringSpringMvcMybatis集成 框架集成核心,如果你的项目中,用到了Spring框架,那么其他框架主要就是和Spring集成; 和Spring集成的核心思路: 把当前框架的核心类,交给Spring管理&#xff08…

WP采集插件的进阶功能:输入关键词采集及定向采集实现精准筛选

WP采集插件教程:轻松实现全网文章采集 近年来,WordPress(简称WP)作为一款强大的网站建设工具,广受用户喜爱。然而,对于许多网站管理员来说,如何轻松而高效地获取全网各类文章内容成为了一个亟待…

AutoCAD 2024 中文

AutoCAD 2024是一款全球知名的计算机辅助设计软件,由Autodesk公司开发。它提供了丰富的绘图功能和工具,可以满足不同领域的需求,支持2D和3D绘图设计,包括平面图、立体图、剖面图等等。此外,AutoCAD 2024具备强大的数据…

明基|书客|松下护眼台灯值不值得买?爆款多维度测评揭晓!

随着近视率越来越高的现象,护眼台灯逐渐成为大多数家庭的日常所需,许多护眼台灯品牌为了降低价格吸引消费者而不惜大程度上降低材料品质,导致台灯寿命减短,光线变差等问题频发,这也让广大对于如何选择一款好的护眼台灯…

QListWidget中自定义widget大小自适应

背景: QListWidget中的item,可以添加自定义的widget。 但是怎么去调整widget的大小呢? 参考:QT QListWidget的添加与删除,滚动条显示或隐藏,判断是否滑到顶部或底部,并使QListWidgetItem自适…

vue3 input 上传 vuedraggable 实现拖拽排序

效果如下 input 实现上传功能 通过隐藏 input 元素&#xff0c;点击上传触发 input 点击事件&#xff0c;监听 input change 事件 accept 上传文件的类型 multiple 是否允许上传多个 <template><div class"cursor-pointer" click"submitUpload"&…

零代码集成自动化的实现逻辑是什么?

零代码的概念是什么&#xff1f; 零代码平台是一种软件开发工具或平台&#xff0c;非技术人员能够创建和部署应用程序&#xff0c;而无需编写任何代码。它提供了可视化的界面和拖拽式的操作&#xff0c;使用户能够通过简单的配置和组合&#xff0c;以图形化的方式构建应用程序…

vue2常见的语法糖

Vue.js 2 提供了一些语法糖&#xff08;syntactic sugar&#xff09;来简化常见的操作。以下是一些 Vue.js 2 中常用的语法糖&#xff1a; v-bind 简写&#xff1a; <!-- 完整语法 --> <a v-bind:href"url">Link</a><!-- 简写 --> <a :hr…

Jmeter进阶使用:BeanShell实现接口前置和后置操作!

一、背景 我们使用Jmeter做压力测试或者接口测试时&#xff0c;除了最简单的直接对接口发起请求&#xff0c;很多时候需要对接口进行一些前置操作&#xff1a;比如提前生成测试数据&#xff0c;以及一些后置操作&#xff1a;比如提取接口响应内容中的某个字段的值。举个最常用…

nexus制品库的介绍及详细部署使用

一、nexus 介绍 Nexus 是一个强大的仓库管理工具&#xff0c;用于管理和分发 Maven、npm、Docker 等软件包。它提供了一个集中的存储库&#xff0c;用于存储和管理软件包&#xff0c;并提供了版本控制、访问控制、构建和部署等功能。 Nexus 可以帮助开发团队提高软件包管理的效…

构建强大的接口自动化测试框架:Pytest实践指南!

一. 背景 Pytest目前已经成为Python系自动化测试必学必备的一个框架&#xff0c;网上也有很多的文章讲述相关的知识。最近自己也抽时间梳理了一份pytest接口自动化测试框架&#xff0c;因此准备写文章记录一下&#xff0c;做到尽量简单通俗易懂&#xff0c;当然前提是基本的py…

DevEco Studio设置每次进入 是否自动进入上一次的项目

首先 我们第一次创建项目 并不是这个界面 如果我们想在这个界面创建项目的话 可以 点击左上角 File 下的 New 下的 Create Project 这里 我们可以点击左上角 File 选择下面的 Settings… 这个界面就有非常多的配置 然后 我们选择到下图操作的位置 这里有一个Reopen projects…

适用于 Windows 和 Mac 电脑的最佳数据恢复软件

当我们的电脑上的文件被错误删除时&#xff0c;总是很难恢复该文件&#xff0c;或者除非您进行了系统还原&#xff0c;否则一切都会恢复到删除恢复的文件或文件夹之前的状态。 拥有合适的 PC 软件始终可以帮助您改善 PC 用户的体验&#xff0c;而适用于 Windows 10 和 11 的良…

SQL 金额数值转换成中文大写

需求&#xff1a;将金额转换成中文大写格式填入单据合计行&#xff1a; _佰_拾_万_仟_佰_拾_元_角_分 1234567.89 壹佰贰拾叁万肆仟伍佰陆拾柒元捌角玖分 1.函数转换 drop function n2C;CREATE FUNCTION n2C (num numeric(14,2)) RETURNS VARCHAR(20) AS BEGIN …

linux NAT网卡配置static

由于是内网&#xff0c;资料无法拷贝&#xff0c;借助参考资料&#xff0c;整理发出。 镜像安装 基本操作。 查看VM配置 图1&#xff0c;有几个信息。一个是NAT借用了网卡里的VMnet8适配器。 子网IP是从192.168.142.0 子网掩码255.255.255.255&#xff0c;对应下面配置的N…

【云平台】STM32微信小程序阿里云平台汇总——持续更新

【云平台】STM32微信小程序阿里云平台汇总——持续更新 文章目录 前言总结 前言 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 【云平台】STM32微信小程序阿里云平台学习板 【云平台】小白从零开始&#xff1a;小程序阿里云平台控制STM32&#xff08…
最新文章