- 浏览: 633450 次
- 性别:
- 来自: 武汉
文章分类
最新评论
-
lizhuang:
这个方法的内部实现主要是依赖于类加载器,一般的自己实现的类是用 ...
Java中getResourceAsStream的用法 -
prince4426:
回答评论都很精彩
Java中getResourceAsStream的用法 -
kexuetou:
美人如此多娇 写道可能这样总结更好,路径前不带'/',则是相对 ...
Java中getResourceAsStream的用法 -
guoxin91:
...
Java中getResourceAsStream的用法 -
美人如此多娇:
可能这样总结更好,路径前不带'/',则是相对路径;若带,则是绝 ...
Java中getResourceAsStream的用法
引言
wchar_t wch = L''1''; // 2 bytes, 0x0031 wchar_t* wsz = L"Hello"; // 12 bytes, 6 wide characters
字符在内存中是怎样存储的
Unicode的存储形式,L"Bob"
使用两个字节表示的0来做结束标志。
值得注意的是,"ni"的值不能被解释成WORD型值0xfa93,而应该看作两个值93和fa以这种顺序被作为"ni"的编码。 使用字符串处理函数
因为x86 CPU是little-endian,值0x0042在内存中的存储形式是42 00。你能看出如果这个字符串被传给strlen()函数会出现什么问题吗?它将先看到第一个字节42,然后是00,而00是字符串结束的标志,于是strlen()将会返回1。如果把"Bob"传给wcslen(),将会得出更坏的结果。wcslen()将会先看到0x6f42,然后是0x0062,然后一直读到你的缓冲区的末尾,直到发现00 00结束标志或者引起了GPF。 正确的遍历和索引字符串 我们先来阐述规则2,因为找到一个违背它的真实的实例代码是很容易的。假设你有一个程序在你自己的目录里保存了一个设置文件,你把安装目录保存在注册表中。在运行时,你从注册表中读取安装目录,然后合成配置文件名,接着读取该文件。假设,你的安装目录是C:\Program Files\MyCoolApp,那么你合成的文件名应该是C:\Program Files\MyCoolApp\config.bin。当你进行测试时,你发现程序运行正常。 bool GetConfigFileName ( char* pszName, size_t nBuffSize ) { char szConfigFilename[MAX_PATH]; // Read install dir from registry... we''ll assume it succeeds. // Add on a backslash if it wasn''t present in the registry value. // First, get a pointer to the terminating zero. char* pLastChar = strchr ( szConfigFilename, ''\0'' ); // Now move it back one character. pLastChar--; if ( *pLastChar != ''\\'' ) strcat ( szConfigFilename, "\\" ); // Add on the name of the config file. strcat ( szConfigFilename, "config.bin" ); // If the caller''s buffer is big enough, return the filename. if ( strlen ( szConfigFilename ) >= nBuffSize ) return false; else { strcpy ( pszName, szConfigFilename ); return true; } }这是一段很健壮的代码,然而在遇到 DBCS 字符时它将会出错。让我们来看看为什么。假设一个日本用户使用了你的程序,把它安装在 C:\。下面是这个名字在内存中的存储形式:
当使用 GetConfigFileName() 检查尾部的''\\''时,它寻找安装目录名中最后的非0字节,看它是等于''\\''的,所以没有重新增加一个''\\''。结果是代码返回了错误的文件名。 bool FixedGetConfigFileName ( char* pszName, size_t nBuffSize )
{
char szConfigFilename[MAX_PATH];
// Read install dir from registry... we''ll assume it succeeds.
// Add on a backslash if it wasn''t present in the registry value.
// First, get a pointer to the terminating zero.
char* pLastChar = _mbschr ( szConfigFilename, ''\0'' );
// Now move it back one double-byte character.
pLastChar = CharPrev ( szConfigFilename, pLastChar );
if ( *pLastChar != ''\\'' )
_mbscat ( szConfigFilename, "\\" );
// Add on the name of the config file.
_mbscat ( szConfigFilename, "config.bin" );
// If the caller''s buffer is big enough, return the filename.
if ( _mbslen ( szInstallDir ) >= nBuffSize )
return false;
else
{
_mbscpy ( pszName, szConfigFilename );
return true;
}
}
上面的函数使用CharPrev() API使pLastChar向后移动一个字符,这个字符可能是两个字节长。在这个版本里,if条件正常工作,因为lead byte永远不会等于0x5c。
2a. 永远不要使用减法去得到一个字符串的索引。 违背这条规则的代码和违背规则2的代码很相似。例如, char* pLastChar = &szConfigFilename [strlen(szConfigFilename) - 1]; 这和向后移动一个指针是同样的效果。 回到关于str***()和_mbs***()的区别 Win32 API中的MBCS和Unicode BOOL WINAPI SetWindowTextA ( HWND hWnd, LPCSTR lpString ); BOOL WINAPI SetWindowTextW ( HWND hWnd, LPCWSTR lpString ); #ifdef UNICODE #define SetWindowText SetWindowTextW #else #define SetWindowText SetWindowTextA #endif当使用MBCS APIs来build程序时,UNICODE没有被定义,所以预处理器看到: #define SetWindowText SetWindowTextA 这个宏定义把所有对SetWindowText的调用都转换成真正的API函数SetWindowTextA。(当然,你可以直接调用SetWindowTextA() 或者 SetWindowTextW(),虽然你不必那么做。) HWND hwnd = GetSomeWindowHandle(); char szNewText[] = "we love Bob!"; SetWindowText ( hwnd, szNewText ); 在预处理器把SetWindowText用SetWindowTextW来替换后,代码变成: HWND hwnd = GetSomeWindowHandle(); char szNewText[] = "we love Bob!"; SetWindowTextW ( hwnd, szNewText ); 看到问题了吗?我们把单字节字符串传给了一个以Unicode字符串做参数的函数。解决这个问题的第一个方案是使用 #ifdef 来包含字符串变量的定义: HWND hwnd = GetSomeWindowHandle(); #ifdef UNICODE wchar_t szNewText[] = L"we love Bob!"; #else char szNewText[] = "we love Bob!"; #endif SetWindowText ( hwnd, szNewText ); 你可能已经感受到了这样做将会使你多么的头疼。完美的解决方案是使用TCHAR. 使用TCHAR #ifdef UNICODE typedef wchar_t TCHAR; #else typedef char TCHAR; #endif 所以用MBCS来build时,TCHAR是char,使用UNICODE时,TCHAR是wchar_t。还有一个宏来处理定义Unicode字符串常量时所需的L前缀。 #ifdef UNICODE #define _T(x) L##x #else #define _T(x) x #endif ##是一个预处理操作符,它可以把两个参数连在一起。如果你的代码中需要字符串常量,在它前面加上_T宏。如果你使用Unicode来build,它会在字符串常量前加上L前缀。 TCHAR szNewText[] = _T("we love Bob!"); 像是用宏来隐藏SetWindowTextA/W的细节一样,还有很多可以供你使用的宏来实现str***()和_mbs***()等字符串函数。例如,你可以使用_tcsrchr宏来替换strrchr()、_mbsrchr()和wcsrchr()。_tcsrchr根据你预定义的宏是_MBCS还是UNICODE来扩展成正确的函数,就像SetWindowText所作的一样。 字符串和TCHAR typedefs
何时使用 TCHAR 和 Unicode Windows 9x 中大多数的 API 没有实现 Unicode 版本。所以,如果你的程序要在windows 9x中运行,你必须使用MBCS APIs。然而,由于NT系统内部都使用Unicode,所以使用Unicode APIs将会加快你的程序的运行速度。每次,你传递一个字符串调用MBCS API,操作系统会把这个字符串转换成Unicode字符串,然后调用对应的Unicode API。如果一个字符串被返回,操作系统还要把它转变回去。尽管这个转换过程被高度优化了,但它对速度造成的损失是无法避免的。
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
作者简介 |
发表评论
-
main中调用dll中的函数,F10单步到main的右大口号时出现user breakpoint called...
2010-03-09 18:42 1734在dll中输出了一个包含string类子对象的类,在DEBUG ... -
VC中链接动态链接库的方法
2010-03-06 17:17 1335方法一:windows提供了一套函数,用于加载动态链接库中的符 ... -
50个C/C++源代码网站
2010-01-30 13:01 2930C/C++是最主要的编程语言。这里列出了50名优秀网站和网页清 ... -
《Effective C++》条款34: 将文件间的编译依赖性降至最低
2010-01-29 21:04 2066假设某一天你打开自己的C++程序代码,然后对某个类的实现做了小 ... -
QHttp
2010-01-26 17:06 6956QHttp是Qt所提供有关网络的高阶API,可以协助我们进行H ... -
VC屏蔽Enter和ESC退出程序
2010-01-15 21:51 2400重载PreTranslateMessage函数屏蔽回车和ESC ... -
《Effective C++》条款22:尽量用"传引用"代替"传值"
2010-01-13 11:15 2874c语言中,什么都是通过传值来实现的,c++继承了这一传统并将它 ... -
《高质量C++/C 编程指南》之 内存耗尽怎么办
2010-01-12 14:20 1574如果在申请动态内存时找不到足够大的内存块,malloc ... -
《高质量C++/C 编程指南》之 常见的内存错误及其对策
2010-01-12 14:10 1436发生内存错误是件非 ... -
《高质量C++/C 编程指南》之 有了malloc/free为什么还要new/delete
2010-01-12 13:33 1692malloc与free是C++/C语言的标准库函 ... -
《高质量C++/C 编程指南》之 free和delete把指针怎么啦?
2010-01-12 11:30 1212别看free和delete的名字恶狠狠的(尤其是delete) ... -
《高质量C++/C 编程指南》之 杜绝"野指针"
2010-01-12 11:27 1271“野指针”不是NULL指针,是指向“垃圾”内存的指针。人们一般 ... -
《Effective C++》条款14: 确定基类有虚析构函数
2010-01-12 11:18 5114有时,一个类想跟踪它 ... -
数组名不完全等于指针
2010-01-10 19:12 1773指针是C/C++语言的特色,而数组名与指针有太多的相似,甚至很 ... -
C++字符串完全指引之二
2010-01-09 16:16 1474引言 因为C语言 ... -
BMP文件格式
2010-01-08 22:15 1816一.位图结构如下: ---- 一、BMP文件结构 --- ... -
OpenCV基础数据结构
2010-01-08 21:56 2141图像数据结构: 1) IPL ... -
OpenCV基本知识
2010-01-08 21:31 29451、OpenCV概述 1) 什么是OpenCV 开 ... -
calloc(), malloc(), realloc(), free()
2010-01-08 21:08 1401void *calloc(size_t nobj, size_ ... -
善用GetLastError函数
2010-01-08 21:06 2156在编程过程中,当程序出现错误,却又不知道错误的原因 ...
相关推荐
C++字符串完全指引之一 Win32 字符编码 C++字符串完全指引之二 字符串封装类 详细介绍了c++字符编码和字符串相关类
传统Ansi(单字节字符)和Unicode(双字节字符,又称为宽字符)介绍以及Win32对它们的支持.
一份字符串资料,细节很多,用来参看不错。
vc学习笔记,自己的和从网站上找的 VC6的字符串到VC2008中的使用说明 C++字符串完全指引
第4章 内核字符串与内存 38 4.1 字符串的处理 39 4.1.1 使用字符串结构 39 4.1.2 字符串的初始化 41 4.1.3 字符串的拷贝 42 4.1.4 字符串的连接 42 4.1.5 字符串的打印 43 4.2 内存与链表 45 ...
第4章 内核字符串与内存 38 4.1 字符串的处理 39 4.1.1 使用字符串结构 39 4.1.2 字符串的初始化 41 4.1.3 字符串的拷贝 42 4.1.4 字符串的连接 42 4.1.5 字符串的打印 43 4.2 内存与链表 45 ...
第4章 内核字符串与内存 38 4.1 字符串的处理 39 4.1.1 使用字符串结构 39 4.1.2 字符串的初始化 41 4.1.3 字符串的拷贝 42 4.1.4 字符串的连接 42 4.1.5 字符串的打印 43 4.2 内存与链表 45 ...
第4章 内核字符串与内存 4.1 字符串的处理 4.1.1 使用字符串结构 4 1 2 字符串的初始化 4.1.3 字符串的拷贝 4.1.4 字符串的连接 4.1.5 字符串的打印 4 2 内存与链表 4 2.1 内存的分配与释放 4.2.2 使用LIST_ENTRY ...
*.ESD 数据表⽂件(带数据保存) SelfData ⽂件夹下的⽂件: *.str 字符串数据 *.oth 与股票⽆关序列值数据 Pattern ⽂件夹下的⽂件 *.PIN 模式匹配设计 *.PWT 模式匹配⽅法 S potAna ⽂件夹下的⽂件 : *.SPT 定位...