马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
本帖最后由 新手学习中 于 2014-3-16 19:28 编辑
窄字节与宽字节
1、什么是窄字节,什么是宽字节:
英文字符,其大小为1字节的,叫窄字节
英文字符,其大小为2字节的,叫宽字节
2、不管编译器宽窄设置,中文字符默认占2字节,英文字符默认占1字节
如: sizeof(‘你’) 结果是2 ,不管编译器如何设置宽窄
sizeof("你");结果3 中文2字节,结束符1字节 双引号表示字符串,自动添加结束符
sizeof('abc');结果是3 单引号是字符,没有结束符,每个英文字符占1字节
sizeof(''abc'');结果是4
3、字符实际储存的大小可人为改变,英文可以变大,中文变小会出错
英文字符可转换成一个字符占2字节。如:
sizeof(L'abc');结果6 L表示强行把一个字符变成两字节,这也就是宽字节,其实是用0填充了高位
sizeof(L'我bc');结果6 当然中文默认是2字节,L之后还是2字节
char m = '你' ; 编译没错,但是这里把原本2字节的,给了只有1字节空间的m ,结果数据丢失,运行显示时会有乱码
要正常显示,需要用多个char表示 ,如char m []= '你' ;
WCHAR m = L 'a'; 转为宽字节后,需要2字节大小的类型来储存。
4、什么是窄字节环境,什么是宽字节环境:
编译器设置可设置为宽字节环境或者窄字节环境。
其区别就是:根据设置不同,把通用类型转换成窄或者宽类型。以及一些有两种类型的函数
如:数据类型
T 通用类型:TCHAR 头文件tchar.h
如果是窄字节环境,TCHAR转为CHAR
TCHAR m = 'a';
CHAR m ='a';
如果是宽字节环境,TCHAR转为wchar_t
wchar_t数据类型大小为2字节。
TCHAR m =L 'a'; //一定要加上L 否则报错
WCHAR m = L 'a'; //一定要加上L 否则报错
如:通用函数 _T(x) 函数把字符串参数转换成宽或者窄
宽环境:
_T("abc"); 8字节
窄环境 :
_T("abc");4字节,也可以直接写成 "abc"
编程时,最好使用通用类型,因为方便日后修改。
MessageBox---MessageBoxA 和 MessageBoxW
如果系统设置窄---则MessageBox变成MessageBoxA
如果系统设置宽---则MessageBox变成MessageBoxW
5、为何中文字符需要两个字节储存
英文字符只有a~z 大小写总的也就48种。
一个字节8位二进制,其数字的01组合种类完全满足其个数。255个字符
但是一个中文字符,却有太多种不同。所以一个字节8位的排列组合无法满足其个
数。
所以又了两个字节16位来表示一个中文字符。(还要表示韩文,日文等)
6、编译器的默认
vc++ 6.0 默认为Ansi编码,vs2005、vs2008、vs2010 等默认都是Unicode编码
7、为何建议把环境设置成宽字节
如果是窄字节环境,其程序在日文环境,韩文环境等可能会出现乱码
原因涉及一些底层原理。
宽字节把所有字符都以2字节储存,所以缺点是占用空间大。
8、什么时候必须进行窄宽转换
某些API只提供窄版本或者宽版本。但使用其返回值等又必须转换才能给其他使用
。
比如GetProcAddress
其第二个参数是指向窄字节的指针。不可指向宽字节。
9、一些数据类型不仅根据宽窄而变,而且还会根据根据系统而改变
比如size_t
编译器中定义为:
#ifndef _SIZE_T_DEFINED
#ifdef _WIN64
typedef unsigned __int64 size_t; //8个字节,64位
#else
typedef _W64 unsigned int size_t; //4个字节,32位
#endif
#define _SIZE_T_DEFINED
#endif
********************************************************************************** ********************************************************************************** ********************************************************************************** **********************************************************************************
10、如何对字符变量进行窄宽转换
WideCharToMultiByte 实现宽字节转换到窄字节,也可统计字符长度(根据参数不同还能转换成其他类型)
MultiByteToWideChar 实现窄字节转换到宽字节
关键代码:
int needBytes = WideCharToMultiByte(CP_ACP, 0, pWideChar, -1, NULL, 0, NULL, NULL);
WideCharToMultiByte(CP_ACP, 0, pWideChar, -1, pszBuf, needBytes, NULL, NULL);
说明:
1、pWideChar表示待转换的字符串指针,-1表示长度为总字符个数-总长度(包含结束符),其他参数照上面传。
2、第一次调用没传转换后的缓冲区,函数的功能是返回总长度
3、第二次调用,需要传入缓冲区指针:
pszBuf = new char[needBytes+1];
注意,这里是needBytes+1。因为转换的时候,是把包含结束符整个长度给转换了。而空间本身还需要预留一个结束符。
实际上,转换后是有两个结束符。
4、虽然我们申请了needBytes+1,但是传参数的时候,是传needBytes,因为能用的只有needBytes长度。
int needWChar = MultiByteToWideChar(CP_ACP, 0, pChar, -1, NULL, 0);
MultiByteToWideChar(CP_ACP, 0, pChar, -1, pszBuf, needWChar);
11、获取字符串长度(字符个数)的函数
Ansi:strlen(char *str);
Unicode:wcslen(wchar_t *str);
注意:strlen获取的长度不包含结束符,也就是说,他碰到结束符\0就结束。如果字符是"ab\0ab"
那么长度就是2。
12、获取字符串占用字节数:
Ansi:
char szStr[] = "abc";
sizeof(szStr);
char *psz = "defgh";
(strlen(psz)+1)*sizeof(char); //求总字节数
strlen(psz)*sizeof(char); //有效字节数
注意:strlen(psz) 求出的长度不包含结束符,碰到\0结束统计。如果是"ab\0ab"那么其统计的结果就是2
注意:不可用sizeof(psz),这只是统计指针变量字节数。
但是如果换成数组名,那就是数组总字节数。(因为这个是指针常量)
Unicode:
wchar_t szwStr[] = L"abc";
sizeof(szwStr); wchar_t *pwsz = L"defgh";
wcslen(pwsz)*sizeof(wchar_t);
(wcslen(pwsz)+1)*sizeof(wchar_t);
通用函数求字节数:
TCHAR szStr[] = _T("abc");
sizeof(szStr);
TCHAR *psz = _T("defgh");
_tcslen(psz)*sizeof(TCHAR);
(_tcslen(psz)+1)*sizeof(TCHAR);
12、简单宽窄转换方式:A2W、W2A、T2A、T2W
返回值就是转换好的字符串 #include <atlbase.h>
如:
void f()
{
USES_CONVERSION;
wchar_t * p = A2W("abc");
}
说明:
1、包含头文件#include <atlbase.h>
2、使用之前必须要加 USES_CONVERSION;
3、此为静态空间,会自动释放
注意:不可“直接”在循环里使用:如:
void func()
{
while(true)
{
{
USES_CONVERSION;
A2W("abc");
}
}
}
原因:
出括号范围后,局部变量依然存在,只有销毁活动记录后,局部变量才跟着销毁。但是出了括号就出了变量的作用域,没法通过变量名直接访问。( c专家编程 第125页)
意思就是说,大括号出来后,变量没被释放,但不能访问,只有函数结束后才会被释放,因此这个循环导致内存无法被释放。
解决方法:让其包含在函数里:如:
void fn2()
{
USES_CONVERSION;
DoSomething(A2W("SomeString"));
} void fn()
{
while(true)
{
fn2();
}
}
头文件包含:
A2W ------- #include <atlbase.h>
TCHAR wchar_t ------#include"tchar.h"
WideCharToMultiByte ------ #include <windows.h>
13、vc6.0如何修改成宽字节。
打开[工程]->[设置…]对话框,在C/C++标签对话框的“预处理程序定义”中去除_MBCS,加上_UNICODE,UNICODE。(注意中间用逗号隔开)
如果是MFC:
因为MFC应用程序有针对Unicode专用的程序入口点,我们要设置entry point。否则就会出现连接错误。
设置entry point的方法是:打开[工程]->[设置…]对话框,在Link页的Output类别的Entry Point里填上wWinMainCRTStartup
|