C/C++宽窄字符转换与输出的多种实现方法

 更新时间:2022年08月08日 08:27:41   作者:IT余识  
本文主要介绍了C/C++宽窄字符转换与输出的多种实现方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

前言

如果是C/C++程序员,对于VS应该是不陌生的,可谓是C/C++程序手中的利器

但如果稍微深入学习就会发现,windows API大部分都是分为宽字节与窄字节的,比如常见的MessageboxA与MessageBoxW函数,这时候就会出现很多问题,最常见的便是乱码

需要注意的是,WIndows底层函数均采用的是宽字节,即使你使用的是char,程序真正执行的时候,还是会在底层将char转化为wchar_t,这就意味着使用窄字节效率是比不上宽字节

同时需要知道.wchar_t是支持多个国家语言的,而char只支持本国语言.

一、什么是宽字节?什么是窄字节?

认识宽窄字节最好的办法就是动手实验一下

可以看到,最直接的影响就是大小,char只占一个字节,而wchar_t要占两个字节,并且需要在字符串前加 L 才表示是宽字节

其实还有很多细节,比如这里是使用的字符c,如果是使用的汉字,还能正常使用吗?很多问题需要自己碰到并解决,最后才能是自己的东西

二、宽窄字节之间的转化方法

1.Windows API进行转化

头文件:

#include<Windows.h>

用到的函数

窄字节转宽字节:

int MultiByteToWideChar(
UINT    CodePage,  //要转换的代码页,一般直接填CP_ACP,表示当前系统使用的代码页
DWORD   dwFlags, //转换标志,直接填0即可
LPCCH lpMultiByteStr, //要转换的窄字节字符串
int   cbMultiByte, //窄字节字符串的长度,以字节计算
LPWSTR  lpWideCharStr, //存放转换完成的宽字符缓冲区
int    cchWideChar //存放宽字符缓冲区的大小
);

宽字节转窄字节:

int WideCharToMultiByte(
UINT CodePage,//要转换的代码页,一般直接填CP_ACP,表示当前系统使用的代码页
 DWORD dwFlags,//转换标志,直接填0即可
LPCWCH lpWideCharStr,//要转换的宽字节字符串
int cchWideChar, //宽字节字符串的长度,以字符计算
LPSTR lpMultiByteStr, //存放转换完成的窄字符缓冲区
 int cbMultiByte, //存放宽字符缓冲区的大小
LPCCH lpDefaultChar, //如果字符无法转换,则使用该字符填充,一般填0,默认即可
LPBOOL lpUsedDefaultChar //如果出现无法转换的字符,该参数被设为true,默认填NULL即可
);

一般宽字符是窄字符字节长度的两倍,但也有可能出现意外情况,或者不想自己计算需要多大的缓冲,则可以调用两次该函数,第一次返回需要的大小,第二次进行转换

下面是我封装的两个函数,可直接使用,但需要自己delete内存,可以自己使用wstring和string进行替换

窄字节转宽字节:

//str:要转换的窄字符串
//len:接受转换成功后宽字符的长度,可直接填NULL,不接收
wchar_t* AtoW(const char* str, int* len)
{
	int wcLen = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
	wchar_t* newBuf = new wchar_t[wcLen + 1]{};
	MultiByteToWideChar(CP_ACP, 0, str, -1, newBuf, wcLen);
	if (len != NULL) {
		*len = wcLen;
	}
	return newBuf;
}

宽字节转窄字节

//str:要转换的宽字符串
//len:接受转换成功后窄字符的长度,可直接填NULL,不接收
char* WtoA(const wchar_t* str, int* len)
{
	int cLen = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, 0, NULL);
	char* newBuf = new char[cLen + 1]{};
	WideCharToMultiByte(CP_ACP, 0, str, -1, newBuf, cLen, 0, NULL);
	if (len != NULL) {
		*len = cLen;
	}
	return newBuf;
}

2.C/C++库函数转换

用到的头文件:

#include<cstdlib> //包含转换函数
#include<locale> //包含设置地域函数

用到的函数:

设置地域,当试图转换中文时,需要设置,否则为乱码

char* setlocale(
int  _Category, //设置该函数影响范围,一般直接填LC_ALL,即全部影响
char const* _Locale //一般填空,即使用本地地域信息
);

标准窄转宽:

size_t mbstowcs(
wchar_t    _Dest, //转换后存放的地方
const char * _Source, //要转换的内容
size_t   _MaxCount //转换后存放地方的大小,以字符个数计算
)

使用:

#define _CRT_SECURE_NO_WARNINGS //必须定义宏,否则VS报错
#include<iostream>
#include<cstdlib>
#include<locale>
using namespace std;
int main() {
	setlocale(LC_ALL, ""); //设置本地地域信息.否则转换中文出现乱码
	wchar_t buf[0xFF];
	mbstowcs(buf, "哈哈哈哈", 0xFF);
}

标准宽转窄:

size_t wcstombs(
char*_Dest, //转换后存放的地方
const wchar_t* _Source, //要转换的内容
size_t   _MaxCount //转换后存放地方的大小,以字符个数计算
)

使用:

#define _CRT_SECURE_NO_WARNINGS //必须定义宏,否则VS报错
#include<iostream>
#include<cstdlib>
#include<locale>
using namespace std;
int main(){
	setlocale(LC_ALL,""); //设置本地地域信息.否则转换中文出现乱码
	char buf[0xFF];
	wcstombs(buf,L"哈哈哈哈哈",sizeof(buf));
}

安全函数窄转宽:

errno_t mbstowcs_s(
size_t* _PtNumOfCharConverted, //接收转换成功的字符个数
 wchar_t*    _DstBuf, //接受成功转换的字符
size_t  _SizeInWords, //_DesBuf缓冲区大小,以字符计算
 char const* _SrcBuf, //要转化的字符
 size_t      _MaxCount //最大要转化的字符数量
    );

使用:

#include<iostream>
#include<cstdlib>
using namespace std;
int main() {
	wchar_t buf[0xFF];
	mbstowcs_s(NULL,buf,0xFF, "哈哈哈哈", 0xFF);
}

安全函数宽转窄:

errno_t wcstombs_s(
size_t* _PtNumOfCharConverted, //接收转换成功的字符个数
 wchar_t*    _DstBuf, //接受成功转换的字符
size_t  _SizeInWords, //_DesBuf缓冲区大小,以字符计算
 char const* _SrcBuf, //要转化的字符
 size_t      _MaxCount //最大要转化的字符数量
    );

使用:

#include<iostream>
#include<cstdlib>
#include<locale>
using namespace std;
int main() {
	setlocale(LC_ALL,"");
	char buf[0xFF];
	wcstombs_s(NULL, buf, 0xFF, L"哈哈哈哈哈", sizeof(buf));
	printf("%s",buf);
}

大家可能看到,我有时使用了setlocal,有时没有使用,这个可以根据具体情况而定,如果出现中文无法转化的情况,就要考虑使用这个函数了

而且我都没有接收转化字符个数,也就是第一个参数,如果需要准确接受转化成功字符的个数,就必须要使用setlocal函数

可能大家还看到过_wcstombs_s_l等函数,这个函数还需要_create_locale与 _free_locale函数配合使用,考虑下来,过于麻烦,不如上面的几种转化方法,所以便不予讲解,大家有兴趣可以去查看官网说明,链接在此 函数说明 设置本地说明

3.ATL库转换

ATL模板库是微软推出的一个C++模板库,在visual studio中安装了C++开发环境就可以正常使用

宽转窄:

#include<iostream>
#include<atlconv.h> //头文件
using namespace std;
int main() {
    USES_CONVERSION; //必须添加
    wchar_t buf[] = L"哈哈哈哈哈哈";
    char *nbuf=W2A(buf); //使用栈空间进行转换,不需要delete
    cout << nbuf << endl;
}

窄转宽:

#include<iostream>
#include<locale>
#include<atlconv.h> //头文件
using namespace std;
int main() {
    setlocale(LC_ALL,""); //本地化,为输出汉字
    USES_CONVERSION; //必须添加
    char buf[] = "哈哈哈哈哈哈";
    wchar_t *nbuf=A2W(buf); //使用栈空间进行转换,不需要delete
    wcout << nbuf;
}

4.COM组件转换

宽转窄:

#include<comutil.h>
#pragma comment(lib, "comsuppw.lib")
int main() {
	wchar_t str[] = L"哈哈哈";
	char *s=_com_util::ConvertBSTRToString(str); //转换函数
	//其它操作
	delete[] s; //释放内存
}

窄转宽:

#include<comutil.h>
#pragma comment(lib, "comsuppw.lib")
int main() {
	char str[] = "哈哈哈哈";
	wchar_t *s=_com_util::ConvertStringToBSTR(str); //转换函数
	//其它操作
	SysFreeString(s); //释放内存
}

三.解决VS控制台无法输出宽字符问题

方法一:使用setlocal和printf函数:

#include<iostream>
#include<locale>
using namespace std;
int main() {
	setlocale(LC_ALL,"");
	printf("%ls",L"了解");
}

方法二:使用setlocal与wcout

#include<iostream>
#include<locale>
using namespace std;
int main() {
	setlocale(LC_ALL,"");
	wcout << L"哈哈哈哈啊";
}

以上两种方法,如果宽字符串中没有中文字符,则可不使用setlocal函数

方法三:使用WriteConsoleW函数

#include<Windows.h>
int main() {
	wchar_t buf[]=L"哈哈哈哈哈哈哈哈哈哈";
	WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE),buf,sizeof(buf)/2, NULL, 0);
}

到此这篇关于C/C++宽窄字符转换与输出的多种实现方法的文章就介绍到这了,更多相关C/C++宽窄字符转换与输出内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C语言修炼之路悟彻数组真妙理 巧用下标破万敌上篇

    C语言修炼之路悟彻数组真妙理 巧用下标破万敌上篇

    在C语言和C++等语言中,数组元素全为指针变量的数组称为指针数组,指针数组中的元素都必须具有相同的存储类型、指向相同数据类型的指针变量。指针数组比较适合用来指向若干个字符串,使字符串处理更加方便、灵活
    2022-02-02
  • Qt中CQGUI框架之阴影圆角窗口实现

    Qt中CQGUI框架之阴影圆角窗口实现

    这篇文章主要介绍了Qt中CQGUI框架之阴影圆角窗口实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-03-03
  • C语言实现猜数字游戏

    C语言实现猜数字游戏

    这篇文章主要为大家详细介绍了C语言实现猜数字游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-11-11
  • C语言实现线性动态(单向)链表的示例代码

    C语言实现线性动态(单向)链表的示例代码

    本文主要介绍了C语言实现线性动态(单向)链表的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-05-05
  • 使用C语言中的time函数获取系统时间

    使用C语言中的time函数获取系统时间

    在C语言中可以使用time函数来获取系统时间,以下对time函数进行了介绍,需要的朋友可以过来参考下
    2013-07-07
  • C++ 类模板与成员函数模板示例解析

    C++ 类模板与成员函数模板示例解析

    这篇文章主要为大家介绍了C++ 类模板与成员函数模板示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-01-01
  • C语言实现快速排序改进版

    C语言实现快速排序改进版

    这篇文章主要为大家详细介绍了C语言实现快速排序的改进代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-08-08
  • C++ 命名空间--namespace总结

    C++ 命名空间--namespace总结

    namespace中文意思是命名空间或者叫名字空间,下面这篇文章主要给大家介绍了关于C++中名称空间namespace使用的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起看看吧
    2021-09-09
  • 顺序线性表的代码实现方法

    顺序线性表的代码实现方法

    下面小编就为大家带来一篇顺序线性表的代码实现方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-04-04
  • C/C++中多态性详解及其作用介绍

    C/C++中多态性详解及其作用介绍

    这篇文章主要介绍了C/C++中多态性(polymorphism)详解及其作用介绍,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-09-09

最新评论