gcc处理gcc 宽字符符类型问题

对于宽字符文件的读写乱码方法处理
再打开文件时,先调用 setlocale(LC_ALL,"chs");
之后用fwopen 打开文件即可,
C 和 C++ 的标准库分别有自己的 locale 操作方法,C 标准库的 locale 设定函数是 setlocale(),而 C++ 标准库有 locale 类和流对象的 imbue() 方法。这篇讲解 C 标准库中 setlocale() 的使用。
GNU libc 中的 setlocale()
头文件与声明如下:
#include &locale.h&
char* setlocale(int category, const char* locale);
category:为locale分类,表达一种locale的领域方面,通常有下面这些预定义常量:LC_ALL、LC_COLLATE、LC_CTYPE、LC_MESSAGES、LC_MONETARY、LC_NUMERIC、LC_TIME,其中 LC_ALL 表示所有其它locale分类的并集。
locale:为期望设定的locale名称字符串,在Linux/Unix环境下,通常以下面格式表示locale名称:language[_territory][.codeset][@modifier],language 为 ISO 639 中规定的语言代码,territory 为 ISO 3166 中规定的国家/地区代码,codeset 为字符集名称。
在Linux下,可以使用 locale -a 命令查看系统中所有已配置的 locale。用不带选项的 locale 命令查看当前 Shell 中活动的 locale。用 locale -m 命令查看locale系统支持的所有可用的字符集编码。
和locale相关的包叫做:locales,locale系统支持的所有可用locale在文件:/usr/share/i18n/SUPPORTED 中列出。
在Debian下,可用 dpkg-reconfigure locales 命令重新配置 locale,也可以手工修改/etc/locale.gen 文件,然后运行 locale-gen 命令。
在Ubuntu下,修改 /var/lib/locales/supported.d/local 文件,配置新的 locale,然后运行 locale-gen 命令。
当 locale 为 NULL 时,函数只做取回当前 locale 操作,通过返回值传出,并不改变当前 locale。
当 locale 为 "" 时,根据环境的设置来设定 locale,检测顺序是:环境变量 LC_ALL,每个单独的locale分类LC_*,最后是 LANG 变量。为了使程序可以根据环境来改变活动 locale,一般都在程序的初始化阶段加入下面代码:setlocale(LC_ALL, "")。
当C语言程序初始化时(刚进入到 main() 时),locale 被初始化为默认的 C locale,其采用的字符编码是所有本地 ANSI 字符集编码的公共部分,是用来书写C语言源程序的最小字符集(所以才起locale名叫:C)。
当用 setlocale() 设置活动 locale 时,如果成功,会返回当前活动 locale 的全名称;如果失败,会返回 NULL。
Windows/VC CRT 的 setlocale()
参考 MSDN VC8, Run-Time Library Reference:
:设置 locale
:返回当前的 _locale_t 值。
在 Windows CRT 的实现中还有一个使用 wchar_t 作为 locale 名的宽字符版本:_wsetlocale()。因此,也有了使用 _TCHAR 宏版本的 setlocale():_tsetlocale()。
Windows CRT 实现的 setlocale() 和 glibc 版本的头文件与声明相同,使用方法类似,如下:
支持的 locale 分类常量:LC_ALL、LC_COLLATE、LC_CTYPE、LC_MONETARY、LC_NUMERIC、LC_TIME。
请求设定的 locale 名可以为以下格式(参考MSDN:):
lang[_country_region[.code_page]]:虽然形式与 glibc 的相同,当 Windows 的 locale 名并不符合 POSIX 的规范,比如采用 GBK 字符集的大陆中文,POSIX 的名字为:zh_CN.GBK,而在 Windows CRT 中要用:Chinese_People's Republic of China.936,(-_-^)。
lang 字段的可用值参考:
country_region 字段的可用值参考:
code_page 字段的可用值是 Windows 系统支持的代码页编号,参考:
.code_page:可以直接使用代码页来设定 locale,而且可以使用 .OCP、.ACP 两个伪代码页,.OCP 表示从系统获得的当前活动的 OEM 代码页,.ACP 表示从系统获得的活动 ANSI 代码页。
"":根据 Windows 系统环境的活动 ANSI 代码页来设定 locale。.OCP、.ACP、和环境代码页都受控制面板中“区域与语言选项”的设置影响。默认装完简体中文版 Windows 后,活动的 ANSI 代码页为:936(即 GBK),可用 chcp 控制台程序查看活动代码页。
NULL:取回当前 locale,不改变当前 locale。
setlocale() 的作用和使用示例
当向终端、控制台输出 wchar_t 类型的字符时,需要设置 setlocale(),因为通常终端、控制台环境自身是不支持 UCS 系列的字符集编码的,使用流操作函数时(如:printf()),在标准/RT库实现的内部会将 UCS 字符转换成合适的本地 ANSI 编码字符,转换的依据就是 setlocale() 设定的活动 locale,最后将结果字符序列传递给终端,对于来自终端的输入流这个过程刚好相反。
可以用重定向输出流到文件的方法验证上面的机制:无论是 Windows CRT、Linux glibc、Cygwin glibc,使用 wprintf() 打印 wchar_t 字符文本时,重定向到文件的内容总是 GBK、UTF-8 等本地 ANSI 编码,而不会是 UCS 编码。
下面是我写的一个使用 setlocale() 的示例:
#ifdef __GNUC__
#define CSET_GBK "GBK"
#define CSET_UTF8 "UTF-8"
#define LC_NAME_zh_CN "zh_CN"
// ifdef __GNUC__
#elif defined(_MSC_VER)
#define CSET_GBK "936"
#define CSET_UTF8 "65001"
#define LC_NAME_zh_CN "Chinese_People's Republic of China"
// ifdef _MSC_VER
#define LC_NAME_zh_CN_GBK
LC_NAME_zh_CN "." CSET_GBK
#define LC_NAME_zh_CN_UTF8
LC_NAME_zh_CN "." CSET_UTF8
#define LC_NAME_zh_CN_DEFAULT LC_NAME_zh_CN_GBK
void print_current_loc();
int main(int argc, char* argv[])
char* locname = NULL;
const wchar_t* strzh = L"中文字符串";
print_current_loc();
// 使用指定的 locale
locname = setlocale(LC_ALL, LC_NAME_zh_CN_DEFAULT);
if ( NULL == locname )
printf("setlocale() with %s failed./n", LC_NAME_zh_CN_DEFAULT);
printf("setlocale() with %s succeed./n", LC_NAME_zh_CN_DEFAULT);
print_current_loc();
wprintf(L"Zhong text is: %ls/n", strzh);
// 使用运行环境中的 locale 设置
locname = setlocale(LC_ALL, "");
if ( NULL == locname )
printf("setlocale() from environment failed./n");
printf("setlocale() from environment succeed./n");
print_current_loc();
wprintf(L"Zhong text is: %ls/n", strzh);
puts("End of program.");
// 打印当前 locale
void print_current_loc()
char* locname = setlocale(LC_ALL, NULL);
printf("Current locale is: %s/n", locname);
要使上面程序成功编译并执行,需要注意一下几点:
Windows CRT 是不支持 UTF-8 编码作为 locale 的,运行时使用 setlocale(LC_ALL, ".65001") 会失败。
使用 Linux 和 Cygwin 的 glibc 时,要在终端显示正确的中文,需满足以下条件:
不要混用 char 和 wchar_t 版本的流操作函数,否则会导致这些函数运行异常,我用Cygwin GCC 4测试混用 printf() 和 wprintf() 时,程序甚至崩掉,所以要将上面程序中 printf() 语句全注释掉才行。Window CRT 的实现则没有这个问题。
运行环境的 locale 设置要和程序中 setlocale() 设定的 locale 一致,比如:终端的活动字符集、环境变量(一般用 LANG),要设置为 *.UTF-8,才能显示 setlocale(LC_ALL, "zh_CN.UTF-8") 设定的 wchar_t 的中文字符。
用 GCC 编译时,要使用 UTF-8 编码保存源文件,这是 GCC 在编译时,将 wchar_t 文字量(以 L 打头)正确转换为 UCS 编码保存在对象文件中的必需条件,用 Native ANSI 编码(比如:GBK)有 wchar_t 文字量的源文件时,GCC 会编译出错,Linux 和 Cygwin 的 GCC 都有这个约束。另外在 Linux GCC 使用 UCS-4 编码保存 wchar_t,而 Windows 和 Cygwin GCC 使用 UCS-2。
用 wprintf() 时,要用 %ls 表示 wchar_t 的字符串,用 %s 表示 char 的字符串,具体参考:,而 Windows 的实现用 %ls、%s 都可以正确输出 wchar_t 字符串。
这里有一篇 Love Katherine 的:,是对 Linux 使用 wchar_t 的分析。
没有更多推荐了,
加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!sprintf宽字符问题_百度知道
sprintf宽字符问题
我的项目是UNICODE的请问如何使用 sprintf
忘打了,我要将一个浮点数格式化成字符串。SDK下可以使用的函数
C++ 和MFC的都不要
我有更好的答案
用 C 库函数 swprintf原型:int swprintf( wchar_t *buffer, const wchar_t *format [, argument] ... );UNICODE 要定义 宏
_UNICODE 你应当知道的。然后 用 swprintf 代替 sprintf #include &stdio.h& 就有了(如果你用 TCHAR.H 则用 _stprintf)
采纳率:57%
为您推荐:
其他类似问题
sprintf的相关知识
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。宽字符处理函数函数与普通函数对照表
字符分类:
宽字符函数普通C函数描述
iswalnum()
isalnum()
测试字符是否为数字或字母
iswalpha()
isalpha()
测试字符是否是字母
iswcntrl()
iscntrl()
测试字符是否是控制符
iswdigit()
isdigit()
测试字符是否为数字
iswgraph()
isgraph()
测试字符是否是可见字符
iswlower()
islower()
测试字符是否是小写字符
iswprint()
isprint()
测试字符是否是可打印字符
iswpunct()
ispunct()
测试字符是否是标点符号
iswspace()
isspace()
测试字符是否是空白符号
iswupper()
isupper()
测试字符是否是大写字符
iswxdigit()
isxdigit()测试字符是否是十六进制的数字
大小写转换:
宽字符函数 普通C函数描述
towlower()
tolower()
把字符转换为小写
towupper()
toupper()
把字符转换为大写
字符比较:
宽字符函数普通C函数描述
wcscoll()
strcoll()
比较字符串
日期和时间转换:
宽字符函数描述
strftime()
根据指定的字符串格式和locale设置格式化日期和时间
wcsftime()
根据指定的字符串格式和locale设置格式化日期和时间,
并返回宽字符串
strptime()
根据指定格式把字符串转换为时间值,
是strftime的反过程
打印和扫描字符串:
宽字符函数描述
fprintf()/fwprintf()
使用vararg参量的格式化输出
fscanf()/fwscanf()
格式化读入
printf()
使用vararg参量的格式化输出到标准输出
从标准输入的格式化读入
sprintf()/swprintf()
根据vararg参量表格式化成字符串
sscanf()
以字符串作格式化读入
vfprintf()/vfwprintf()
使用stdarg参量表格式化输出到文件
vprintf()
使用stdarg参量表格式化输出到标准输出
vsprintf()/vswprintf()
格式化stdarg参量表并写到字符串
数字转换:
宽字符函数 普通C函数描述
wcstod()
strtod()
把宽字符的初始部分转换为双精度浮点数
wcstol()
strtol()
把宽字符的初始部分转换为长整数
wcstoul()
strtoul()
把宽字符的初始部分转换为无符号长整数
多字节字符和宽字符转换及操作:
宽字符函数描述
根据locale的设置确定字符的字节数
mbstowcs()
把多字节字符串转换为宽字符串
mbtowc()/btowc() 把多字节字符转换为宽字符
wcstombs()
把宽字符串转换为多字节字符串
wctomb()/wctob()
把宽字符转换为多字节字符
输入和输出:
宽字符函数 普通C函数描述
fgetwc()
从流中读入一个字符并转换为宽字符
fgetws()
从流中读入一个字符串并转换为宽字符串
fputwc()
把宽字符转换为多字节字符并且输出到标准输出
fputws()
把宽字符串转换为多字节字符并且输出到标准输出串
从标准输入中读取字符,
并且转换为宽字符
getwchar()
getchar()
从标准输入中读取字符,
并且转换为宽字符
使用fgetws()
把宽字符转换成多字节字符并且写到标准输出
putwchar()
putchar()
把宽字符转换成多字节字符并且写到标准输出
使用fputws()
ungetwc()
ungetc()
把一个宽字符放回到输入流中
字符串操作:
宽字符函数 普通C函数描述
wcscat()
strcat()
把一个字符串接到另一个字符串的尾部
wcsncat()
strncat()
类似于wcscat(),
而且指定粘接字符串的粘接长度.
wcschr()
strchr()
查找子字符串的第一个位置
wcsrchr()
strrchr()
从尾部开始查找子字符串出现的第一个位置
wcspbrk()
strpbrk()
从一字符字符串中查找另一字符串中任何一个字符第一次出现的位置
wcswcs()/wcsstr()
strchr()
在一字符串中查找另一字符串第一次出现的位置
wcscspn()
strcspn()
返回不包含第二个字符串的的初始数目
wcsspn()
strspn()
返回包含第二个字符串的初始数目
wcscpy()
strcpy()
拷贝字符串
wcsncpy()
strncpy()
类似于wcscpy(),
同时指定拷贝的数目
wcscmp()
strcmp()
比较两个宽字符串
wcsncmp()
strncmp()
类似于wcscmp(),
还要指定比较字符字符串的数目
wcslen()
strlen()
获得宽字符串的数目
wcstok()
strtok()
根据标示符把宽字符串分解成一系列字符串
wcswidth()
获得宽字符串的宽度
wcwidth()
获得宽字符的宽度
另外还有对应于memory操作的
wmemcpy(),
wmemchr(),
wmemcmp(),
wmemmove(),
wmemset().
没有更多推荐了,
加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!宽字符比较问题
[问题点数:20分,结帖人baobaodediaozhui]
本版专家分:164
CSDN今日推荐
本版专家分:164
本版专家分:173
本版专家分:58
本版专家分:21885
2013年3月 VC/MFC大版内专家分月排行榜第一2013年2月 VC/MFC大版内专家分月排行榜第一2013年1月 VC/MFC大版内专家分月排行榜第一
本版专家分:58
本版专家分:164
本版专家分:432880
2017年 总版技术专家分年内排行榜第一
2014年 总版技术专家分年内排行榜第二
2013年 总版技术专家分年内排行榜第三
2012年 总版技术专家分年内排行榜第七
匿名用户不能发表回复!|
CSDN今日推荐3d,增强现实,跨平台开发.(3d,ar,cross-platform development)
宽字符与窄字符的处理
《windows核心编程》
&Unicode是传递字符串的最佳手段。
C标准库中与wchar_t相关的文件:
《windows核心编程》
文件”string.h”定义了wchar_t数据类型:
typedef unsignedshort wchar_t;
标准的ANSI C函数和它们等价的UNICODE函数:
&所有的U n i c o d e 函数均以w c s 开头,w c s 是宽字符串的英文缩写。若要调用Un i c o d e函数,只需用前缀wc s 来取代AN S I 字符串函数的前缀st r 即可。
&若要建立双重功能,必须包含T C h a r. h 文件,而不是包含S t r i ng . h 文件。
“双重功能”,即为定义的宏,在UNICODE下为哪种使用,在ANSI下又为哪种定义。
文件”tchar.h”定义了TCHAR类型
& T C h a r. h 文件的唯一作用是帮助创建A N S I / U n i c o d e 通用源代码文件。它包含你应该用在源代码中的一组宏,而不应该直接调用st r 函数或者wc s 函数。如果在编译源代码文件时定义了UN I C O D E ,这些宏就会引用wc s 这组函数。如果没有定义_U N I C O D E ,那么这些宏将引用st r这组宏。
&例如,在T C h a r. h 中有一个宏称为_ t c s cp y 。如果在包含该头文件时没有定义_U N I C O D E ,那么_t c s c p y 就会扩展为AN S I 的st r c p y 函数。但是如果定义了_UNICODE,_tcscpy 将扩展为Un i c o d e的wc s c p y 函数。拥有字符串参数的所有C运行期函数都在TC h a r. h 文件中定义了一个通用宏。如果使用通用宏,而不是AN S I / U n i c o d e 的特定函数名,就能够顺利地创建可以为A
N S I 或U n i c od e进行编译的源代码。
_UNICODE和UNICODE
&_ U N I C O D E 宏用于C 运行期头文件,而U N I C OD E 宏则用于Win d o w s 头文件。当编译源代码模块时,通常必须同时定义这两个宏。
windows中与wchar_t相关的文件
《windows核心编程》
定义了UNICODE数据类型的文件:
文件”wtypes.h”定义了windows所有应用的数据类型,包括字符串类型。
#TODO(continue): 既然是定义了所有应用的数据类型,那么应该是不用手动添加的。待测。。
文件”winnt.h”文件
winnt.h文件编译问题,解决方案:
调准包含目录的次序
在include &winnt.h&前include &windows.h&
windows中的UNICODE函数和ANSI函数
windows中的函数名都是大写开头的,windows中的函数类型都是大写开头的,比如整型为UINT, INT, LONG。
windows中许多函数都是”兼容”UNICODE和ANSI字符串。比如CreateWindowEx,它实际上有两种形式:CreateWindowExA和CreateWindowExW。A后缀的表示其中的字符串参数采用的ANSI型字符串,W后缀的表示其中的字符串参数采用的是宽字符型字符串。
操作系统字符串函数名形如:StrCat,StrCpy, StrCmp等。与C运行期字符串函数相似。使用这些函数须加上”shlwapi.h”头文件。
&若要使用这些函数,必须加上S h l WA p i . h 头文件。另外,如前所述,这些字符串函数既有AN S I 版本,也有Un i c o d e 版本,例如St r C a t A 和St r C a t W 。
windows另外提供了一组对unicode和ANSI字符串的操作函数:(这些函数是作为宏实现的,如lstrcat是lstrcatA和lstrcatW宏定义)。使用这些函数须加上”winbase.h”头文件。
lstrcat, lstrcpy, lstrlen,
lstrcmp(对两个字符串进行区分大小写的比较),
lstrcmpi(对两个字符串进行不区分大小写的比较)
转换大小写的函数:使用这些函数须加上”winuser.h”头文件。
PTSTR CharLower(PTSTRpszString);
PTSTR CharUpper(PTSTRpszString);
&其他的C 运行期函数,如i s a l ph a 、is l o w e r 和is u p p e r ,返回一个值,指明某个字符是字母字符、小写字母还是大写字母。WindowsAPI 提供了一些函数,也能返回这些信息:。使用这些函数须加上”winuser.h”头文件。
BOOL IsCharAlpha(TCHARch);
BOOLIsCharAlphaNumerica(TCHAR ch);
BOOL IsCharUpper(TCHARch);
BOOL IsCharLower(TCHARch);
printf函数:sprintf(C标准库提供的函数)和swprintf(操作系统提供的函数即windows函数)
sprintf的使用:在头文件”stdio.h”中
char szA[100];
sprintf(szA, “%s”,“asdf”);
sprintf(szA, ”%S”, L”ASDF”);// 在将宽字符转换为窄字符的时候s须大写
swprintf的使用:在头文件”stdio.h”或”wchar.h”中
wchar_t szW[100];
swprintf(szW, L”%s”,L”SADF”);
swprintf(szW, L”%S”, “SADF”);// 在将窄字符转换为宽字符的时候s须大写
sprintf与sprintf_s,sprint_s_l,swprintf与swprintf_s,swprint_s_l的区别:
sprintf_s 函数在 buffer设置格式并存储一系列字符和值。 每 argument (如果有) 基于在 format相应的格式规范转换和输出。 该格式包括普通字符并具有窗体和功能和的 format 参数相同。 null 字符从右向左书写的最后一个字符之后追加。如果复制出现在重叠的字符串之间,该行为不确定。
sprintf_s 和 sprintf 之间的主要差异是 sprintf_s 检查格式字符串的格式无效字符,sprintf ,而只检查格式字符串或缓冲区是否 NULL 指针。如果任何检查失败,无效参数调用处理程序,如
所述。如果执行允许继续,该函数返回 -1 并将 errno 到 EINVAL。
sprintf_s 和 sprintf 之间的另一个主要区别在于 sprintf_s 带有指定输出区域的大小长度参数在字符。 如果缓冲区为因此打印的文本太小缓冲区设置为空字符串,而无效参数调用处理程序。不同 snprintf, sprintf_s 确保缓冲区将 null 终止 (除非缓冲区大小为零)。
swprintf_s 是 sprintf_s的宽字符版本;为 swprintf_s 的指针参数是宽字符字符串。 编码错误的检测到 swprintf_s 的可能与在 sprintf_s。这些功能的版本与 _l 后缀的相同,只不过它们使用区域设置参数而不是当前线程区域设置。
在 C++ 中,使用这些功能由模板重载简化;重载可推断缓冲区长度 (自动不再需要指定范围参数),并且还可以用以较新,安全重复自动替换旧,不安全的功能。有关更多信息,请参见
具有提供对 sprintf_s 的版本时所发生的其他控件,如果缓冲区太小。 有关更多信息,请参见。
UNICODE与ANSI字符串之间的转换
windows函数:
int MultiByteToWideChar
int MultiByteToWideChar(
UINT CodePage,
//code page
DWORD dwFlags,
//character-type options
LPCSTR lpMultiByteStr,
//address of string to map
int cchMultiByte,
//number of bytes in string
LPWSTR lpWideCharStr,
//address of wide-character buffer
int cchWideChar
//size of buffer
& u C o d e P a ge 参数用于标识一个与多字节字符串相关的代码页号。d w F l a g s 参数用于设定另一个控件,它可以用重音符号之类的区分标记来影响字符。这些标志通常并不使用,在d w F l a g s参数中传递0 。p M u l t i B y t e S t r 参数用于设定要转换的字符串,c c h M u l t i B y t e 参数用于指明该字符串的长度(按字节计算)。如果为c c h M u l t i B y t e 参数传递-
1 ,那么该函数用于确定源字符串的长度。
转换后产生的U n i c o d e 版本字符串将被写入内存中的缓存,其地址由p Wi d e C h a r S t r 参数指定。必须在c c h Wi d e C h a r 参数中设定该缓存的最大值(以字符为计量单位)。如果调用M u l t i B y t e To Wi d e C h a r ,给c c h Wi d e C h a r 参数传递0 ,那么该参数将不执行字符串的转换,而是返回为使转换取得成功所需要的缓存的值。
MultiByteToWideChar(CP_ACP, 0, pMulti8yteStr, -1,
pWideCharStr, nLenOfWideCharStr);
int WideCharToMultiByte
int WideCharToMultiByte(
UINT CodePage,
// code page
DWORD dwFlags,
// performance and mapping flags
LPCWSTR lpWideCharStr, // address of wide-character string
int cchWideChar,
// number of characters in string
LPSTR lpMultiByteStr,
// address of buffer for new string
int cchMultiByte,
// size of buffer
LPCSTR lpDefaultChar,
// address of default for unmappable
// characters
LPBOOL lpUsedDefaultChar
// address of flag set when default
// char. used
&该函数与M u l t i B i t e To Wi d e C h a r 函数相似。同样,u C o d e P a g e 参数用于标识与新转换的字符串相关的代码页。d w F l a g s 则设定用于转换的其他控件。这些标志能够作用于带有区分符号的字符和系统不能转换的字符。通常不需要为字符串的转换而拥有这种程度的控制手段,你将为d w F l a g s 参数传递0 。
p Wi d e C h a r S tr 参数用于设定要转换的字符串的内存地址,c c h Wi d e C h a r 参数用于指明该字符串的长度(用字符数来计量)。如果你为c c h Wi d e C h a r 参数传递- 1 ,那么该函数用于确定源字符串的长度。
转换产生的多字节版本的字符串被写入由p M u l t i B y t e S t r 参数指明的缓存。必须在c c h M u l t i B y t e参数中设定该缓存的最大值(用字节来计量)。如果传递0 作为Wi d e C h a r To M ul t i B y t e 函数的c c h M u l t i B y te 参数,那么该函数将返回目标缓存需要的大小值。通常可以使用将多字节字符串转换成宽字节字符串时介绍的一系列类似的事件,将宽字节字符串转换成多字节字符串。
你会发现,Wi d e C h a r To M u l t i B y t e 函数接受的参数比M u l t i B y t e To Wi d e C h a r 函数要多2 个,即p D e f a u l t C h ar 和p f U s e d D e f a u l t C h a r 。只有当Wi d e C h a r To M u l t i B y t e 函数遇到一个宽字节字符,而该字符在u C o d e P a g e 参数标识的代码页中并没有它的表示法时,Wi d e C
h a r To M u l t i B y t e 函数才使用这两个参数。如果宽字节字符不能被转换,该函数便使用p D e f a u l t C h a r 参数指向的字符。如果该参数是N U L L (这是大多数情况下的参数值),那么该函数使用系统的默认字符。该默认字符通常是个问号。这对于文件名来说是危险的,因为问号是个通配符。
p f U s e d D e f a ul t C h a r 参数指向一个布尔变量,如果宽字符串中至少有一个字符不能转换成等价多字节字符,那么函数就将该变量置为T R U E 。如果所有字符均被成功地转换,那么该函数就将该变量置为FA L S E 。当函数返回以便检查宽字节字符串是否被成功地转换后,可以测试该变量。同样,通常为该测试传递N U L L 。
WideCharToMultiByte(CP_ACP, 0, pWideCharStr, -1,
pMultiByteStr, strlen(pMultiByteStr), NULL, NULL);
#Q: strlen(pMultiByteStr)能取到此数组的大小吗?
先从UNICODE和ANSI的基础开始讲起
一个ANSI字符占一个字节共8位,一个UNICODE字符占两个字节共16位;ANSI字符串以’\0’结束,0x00。
#Q: UNICODE字符串以什么结束??
#A: UNICODE字符串以L”\0”结束,0x0000。
UNICODE和ANSI字符的相关定义及应用在各种运行库中的体现如下:
在C标准库中
UNICODE在C标准库下编译的宏定义为_UNICODE
宽字符的数据类型为wchar_t,窄字符的数据类型为char。数据类型的定义在头文件string.h中,对wchar_t的定义为:
typedef unsigned short wchar_t;
在头文件string.h中,定义了分别对宽字符和窄字符的操作函数,如wcscpy和strcpy等。对宽字符的操作函数和对窄字符的操作函数的对照见:
而在头文件tchar.h中,定义了tchar宏,该文件模块功能实现了”双重功能”。
即例如_tcscpy方法宏,当编译环境定义了UNICODE宏,则此方法宏为wcscpy,不然则为strcpy。等等。。。。
#Q: 对于对宽字符和窄字符的处理函数带后缀_s,如wcscpy_s,strcpy_s,此类方法与wcscpy和strcpy等的区别在哪里?
wcscpy_s方法定义如下:
errno_t wcscpy_s(
wchar_t *strDestination,
size_t sizeInWords,
const wchar_t *strSource
wcscpy方法定义如下:
wchar_t* wcscpy_s(
wchar_t *strDestination,
const wchar_t *strSource
wcscpy_s方法多了一项参数size_tsizeInWords,即要拷贝的字符的个数。这样就可避免strDestination空间分配不足,如此使用更安全!
在windows中
UNICODE在windows下编译的宏定义为UNICODE
windows下定义的数据类型基本上都采用的是全大写的,比如整型INT,无符号整型UINT,wchar_t定义为WCHAR,char定义为CHAR。
#Q: 头文件wtypes.h windef.h winnt.h这三个文件该怎么用???有好多类型都定义串了,这三个文件都是定义在同一级目录下面。
&WINDEF.H 基本数据类型定义。
WINNT.H 支持Unicode的类型定义。
WINBASE.H Kernel(内核)函数。
WINUSER.H 用户界面函数。
WINGDI.H 图形设备接口函数。
&这些定义了Windows的所有资料型态、、和常数识别字,它们是Windows文件中的一个重要部分。
#Q: 头文件windows.h的用法?
&WINDOWS.H是一个最重要的,它包含了其他Windows,这些头文件的某些也包含了其他头文件。
#Q: 头文件windows.h可否直接加载???
#A: 可以。
所以,使用windows最简单最方便的办法就是直接加载头文件windows.h即可:#include &Windows.h&
MFC/Windows基本数据类型
windows中处理UNICODE和ANSI的函数有
定义的宏函数,与C标准库形似的有:
StrCat,StrCpy等等。
在头文件shlwapi.h中如下定义:
#ifdef UNICODE
#define StrCat
#define StrCmp
#define StrCmpI
#define StrCpy
#define StrCpyN
#define StrCatBuff
StrCatBuffW
#define StrCat
#define StrCmp
#define StrCmpI
#define StrCpy
#define StrCpyN
#define StrCatBuff
StrCatBuffA
在头文件winbase.h中定义了以下宏函数:
lstrcat,lstrcpy, lstrlen,
lstrcmp(对两个字符串进行区分大小写的比较),
lstrcmpi(对两个字符串进行不区分大小写的比较)
在头文件winuser.h中:
PTSTRCharLower(PTSTR pszString);
PTSTRCharUpper(PTSTR pszString);
&其他的C 运行期函数,如i s a l ph a 、is l o w e r 和is u p p e r ,返回一个值,指明某个字符是字母字符、小写字母还是大写字母。WindowsAPI 提供了一些函数,也能返回这些信息:
BOOLIsCharAlpha(TCHAR ch);
BOOLIsCharAlphaNumerica(TCHAR ch);
BOOLIsCharUpper(TCHAR ch);
BOOLIsCharLower(TCHAR ch);
windows中对UNICODE和ANSI的处理函数都采用了宏定义,即这样里面用到的参数就是类型就不确定是UNICODE还是ANSI,完全是根据编译环境是否定义了UNICODE/_UNICODE来定。所以参数类型最好采用TCHAR类型,或者是在调用windows方法时进行宏判断:
#ifdef UNICODE
WINFUNC(WCHAR)
WINFUNC(CHAR)
在C++标准库中
这里只讲std::string和std::wstring。
std::string
std::wstring
在MFC中队UNICODE和ANSI的封装使用就是CString了,CString也为一个宏类,即双重类。
&一个CString对象由可变长度的一队字符组成。CString使用类似于Basic的语法提供函数和操作符。连接和比较操作符以及简化的内存管理使CString对象比普通字符串数组容易使用。
CString是基于TCHAR数据类型的对象。如果在你的程序中定义了符号_UNICODE,则TCHAR被定义为类型wchar_t,即16位字符类型;否则,TCHAR被定义为char,即8位字符类型。在UNICODE方式下,CString对象由16位字符组成。非UNICODE方式下,CString对象由8位字符组成。
当不使用_UNICODE时,CString是多字节字符集(MBCS,也被认为是双字节字符集,DBCS)。注意,对于MBCS字符串,CString仍然基于8位字符来计算,返回,以及处理字符串,并且你的应用程序必须自己解释MBCS的开始和结束字节。
讲完了在各个运行环境下对UNICODE和ANSI字符串的操作,现在涉及到的也就是重点中的重点,UNICODE和ANSI字符串之间的转换操作!
wcstombs和wcstombs_s,mbstowcs和mbstowcs_s
定义在头文件stdlib.h中
sprintf和sprintf_s, sprintf_l_s,swprintf和swprintf_s, swprintf_l_s
定义在头文件stdio.h中
MultiByteToWideChar,WideCharToMultiByte
定义在头文件winnls.h中
C标准库、windows、MFC的区别:
C标准库:数据类型、方法均为小写的,未封装
&tchar.h& &string.h&
windows:数据类型大写,方法首字母大写,未封装
&winbase.h& &shlwapi.h& &windows.h&
MFC:数据类型和方法均封装起来了,类以C开头
&afxwin.h&
MFC是对windows的封装。
C标准库中宽字符与窄字符之间的转换
windows核心编程中文版.chm
2.9.1 Windows字符串函数
2.9.4 在Unicode和ANSI之间转换
sprintf && sprintf_s
sprintf定义:
* @param [out] _Dest 输出的目的地址
* @param [in] _Format 输出格式
* @param [in] ... 参数列表
* @retval 返回输出字符的个数
int __cdecl sprintf(char* _Dest,const char* _Format, ...);
sprintf_s定义:
* @param [out] _DstBuf 输出的目的地址
* @param [in] _SizeInBytes 限制按照输出格式_Format转换后的字符个数,同时也限制为_DstBuf分配的缓存空间
* @param [in] _Format 输出格式
* @param [in] ... 参数列表
* @retval 返回输出字符的个数
int __cdecl sprintf_s(char* _DstBuf,size_t _SizeInBytes, const char* _Format, ...);
函数sprintf和sprintf_s的区别:sprintf_s函数多了一个对目的地址分配的空间和转换字符的个数的限制。例:
ASSERT((sizeof(tranStr)/sizeof(char))&= _SizeInBytes);
ASSERT((sizeof(_DstBuf)/sizeof(char))&= _SizeInBytes);
首先判断的是按照输出格式转换的字符串tranStr的个数是否小于等于SizeInBytes,若否,则弹出断言:Bufferto small。可见,在根据_Format进行字符转换时所分配的临时存储空间是由_SizeInBytes来指定的。然后对输出的目的地址_DstBuf的空间大小进行判断,判断其大小是否大于等于_SizeInButes,若否,则可能会出现误用非法空间的可能。不过sprintf_s都为其做了安全处理。所以总的来说,用sprintf_s比用sprintf更安全。
sprintf在对宽窄字符之间的转换的用法在于:
转换窄字符的用法:
char_Dest[100];
sprintf_s(_Dest, 100, "%s","ANSII STR");
其中转换格式必须是小写s;
转换宽字符的用法:
sprintf_s(_Dest, 100, "%S",L"UNICODE STR");
其中转换格式必须是大写S;对比例子:
sprintf_s(_Dest, 100, "%s_%S", "ANSII STR",L"UNICODE STR");
同样,swprintf和swprintf_s的用法:
wchar_t _Dest[100];
swprintf_s(_Dest,100, L”%s_%S”, L”UNICODE STR”, “ANSII STR”);
swprintf && swprintf_s
wcstombs && wcstombs_s
wcstombs的定义:
* @param [in] _MaxCount 限制取出_Source中字符的个数
* @retval 返回转换的字符的个数,包括对结束符的计算
size_t __cdecl wcstombs(char* _Dest,const wchar_t* _Source, size_t _MaxCount);
wcstombs_s的定义:
* @param [out] _PtNumOfCharConverted 返回转换的字符的个数,包括对结束符的计算
* @param [out] _Dst 转换字符存放的目的地址
* @param [in] _DstSizeInBytes 限制取出_Src中字符的个数,同时也限制为_Dst分配的缓存空间
* @param [in] _Src 要转换的字符
* @param [in] _MaxCountInBytes 限制取出_Src中字符的个数
* @retval 返回错误号,为0则表示转换成功
errno_t__cdecl wcstombs_s(size_t* _PtNumOfCharConverted, char* _Dst, size_t_DstSizeInBytes,
const wchar_t* _Src,size_t _MaxCountInBytes);
函数wcstombs_s中参数_DstSizeInBytes起到的作用:对目的地址_Dst分配的缓存空间的限制,若sizeof(_Dst)/sizeof(char) & _DstSizeInBytes,则会提示异常;同时也限制从_Src取出的个数,至于确定取_Src中字符的个数,先是选择_DstSizeInBytes和_MaxCountInBytes中较小的值minNum,然后如果minNum小于wcslen(_Src),则从中取出minNum个字符,再判断_DstSizeInBytes & (minNum
+ 1),为true则出断言。
所以一般的形式为这样:
wcstombs_s(_PtNumOfCharConverted,_Dst, wcslen(_Src) + 1, _Src, _TRUNCATE);
mbstowcs_s(_PtNumOfCharConverted,_Dst, strlen(_Src) + 1, _Src, _TRUNCATE);
wcstombs_s、wcstombs和mbstowcs_s、mbstowcs都是调用的WideCharToMultiByte和MultiByteToWideChar。这里是否可以看成是对WideCharToMultiByte和MultiByteToWideChar的封装使用?
mbstowcs && wcstombs_s
windows中宽字符与窄字符之间的转换
WideCharToMultiByte
MultiByteToWideChar
MFC中宽字符与窄字符之间的转换
MFC中跟字符串相关的有:
CString, CStringList, CStringArray。
目前这些知识暂时够用,已达到解惑的程度,暂结贴!若以后需要继续深入在开贴。
没有更多推荐了,
加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!

我要回帖

更多关于 gcc 类型转换 警告 的文章

 

随机推荐