在windwos中的字符串可分为7-bit的 ASCII标准 , 8-bit ANSI标准和 16-bit Unicode标准。而windows NT 是原生支持Unicode的。所以任何别的标准使用,系统都会把它转换成Unicode。但是着不代表为了效率而只使用Unicode。因为Unicode是使用2 byte来存储字符的,所以它比单字节字符集或则多字节字符集要费内存空间。
CRT中ANSI C标准部分两个字符类型char 和wchar_t char :用双引号括起来的常量,如“general”表示其中每一字符为char型(8位)。这些字符串可以用string.h头文件下的函数处理。如的strlen()
wchar_t:用双引号括起来的前缀加上 L 的常量,如L”wide character”,表示其中每一字符为wchar_t型(一般为16位)。这些字符串用wchar.h头文件中函数处理 。如wcslen()
在CRT中非ANSI C标准部分有一个 tchar.h头文件 该表头文件不是ANSI C标准的一部分,因此那里定义的每个函数和宏定义的前面都有一条底线。tchar.h为需要字符串参数的标准执行时期链接库函数提供了一系列的替代名称(例如,_tPRintf和_tcslen)。有时这些名称也称为「通用」函数名称,因为它们既可以指向函数的Unicode版也可以指向非Unicode版。
如果用预编译指令定义了_UNICODE的标识符并且程序中包含了tchar.h表头文件,那么_tcslen就定义为wcslen
#define _tcslen wcslen
如果没有定义_UNICODE,则_tcslen定义为strlen: #define _tcslen strlen
tchar.h还用一个新的数据型态TCHAR来解决两种字符数据型态的问题。如果定义了_UNICODE标识符,那么TCHAR就是wchar_t: typedef wchar_t TCHAR ;
否则,TCHAR就是char: typedef char TCHAR ;
如果定义了_UNICODE标识符,那么一个称作__T的宏就定义如下 #define __T(x) L##x
那一对井字号称为「粘贴符号(token paste)」,它将字母L添加到宏参数上。因此,如果宏参数是”Hello!”,则L##x就是L”Hello!”。
如果没有定义_UNICODE标识符,则__T宏只简单地定义如下: #define __T(x) x
此外,还有两个宏与__T定义相同:
Tips: 上述名称中 t代表tchar的意思
同样的 tchar.h头文件中还有一个宏_MBCS负责把t开头的函数(宏)转换为处理多字节字符集的函数
windwos中你可以像c/c++标准中一样处理字符串。但是也可以使用独特的windows 单一编码原则。只需要让Windows程序包括表头文件windows.h。该文件包括许多其它表头文件,包括windef.h,该文件中有许多在Windows中使用的基本型态定义,而且它本身也包括winnt.h。winnt.h处理基本的Unicode支持。
winnt的前面包含C的表头文件ctype.h,这是C/C++的众多表头文件之一,包括wchar_t的定义。winnt.h定义了新的数据型态,称作CHAR和WCHAR: typedef char CHAR ; typedef wchar_t WCHAR ; // wc WCHAR定义后面的注释是匈牙利标记法的建议:一个基于WCHAR数据型态的变量可在前面附加上字母wc以说明一个宽字符。 winnt.h表头文件进而定义了可用做8位字符串指针的六种数据型态和四个可用做const 8位字符串指针的数据型态。这里精选了表头文件中一些实用的说明数据型态语句:
typedef CHAR * PCHAR, * LPCH, * PCH, * NPSTR, * LPSTR, * PSTR ; typedef CONST CHAR * LPCCH, * PCCH, * LPCSTR, * PCSTR ;Tips:
前缀N和L表示「near」和「long」,指的是16位Windows中两种大小不同的指标。在Win32中near和long指标没有区别。其中cch为 const char 的意思
类似地,WINNT.H定义了六种可作为16位字符串指针的数据型态和四种可作为const 16位字符串指针的数据型态:
typedef WCHAR * PWCHAR, * LPWCH, * PWCH, * NwpsTR, * LPWSTR, * PWSTR ; typedef CONST WCHAR * LPCWCH, * PCWCH, * LPCWSTR, * PCWSTR ;Tips: c++中有如下宏
#define CONST const
与tchar.h一样,winnt.h将TCHAR定义为一般的字符类型。如果定义了标识符UNICODE(没有底线),则TCHAR和指向TCHAR的指针就分别定义为WCHAR和指向WCHAR的指标;如果没有定义标识符UNICODE,则TCHAR和指向TCHAR的指针就分别定义为char和指向char的指标:
#ifdef UNICODE typedef WCHAR TCHAR, * PTCHAR ;typedef LPWSTR LPTCH, PTCH, PTSTR, LPTSTR ; typedef LPCWSTR LPCTSTR ; #elsetypedef char TCHAR, * PTCHAR ; typedef LPSTR LPTCH, PTCH, PTSTR, LPTSTR ; typedef LPCSTR LPCTSTR ; #endif如果已经在某个表头文件或者其它表头文件中定义了TCHAR数据型态,那么WINNT.H和WCHAR.H表头文件都能防止其重复定义。不过,无论何时在程序中使用其它表头文件时,都应在所有其它表头文件之前包含WINDOWS.H。
winnt.h表头文件还定义了一个宏,该宏将L添加到字符串的第一个引号前。如果定义了UNICODE标识符,则一个称作 __TEXT的宏定义如下: #define __TEXT(quote) L##quote
如果没有定义标识符UNICODE,则像这样定义__TEXT宏: #define __TEXT(quote) quote
此外, TEXT宏可这样定义: #define TEXT(quote) __TEXT(quote)
这与tchar.h中定义_TEXT宏的方法一样,只是不必操心底线。
win32 的链接库文件一般以32结尾,如USER32.DLL,而链接库中字符处理方面的函数都有两个版本(char 类型的和宽字符类型)。如MessageBox就有两个版本。幸运的是,您通常不必关心这个问题,程序中只需使用MessageBox即可。 当使用动态连接来编写windows 程序时,所谓函数“调用”实际会调用user32.dll中真正的函数。这就是所谓的动态连接 而user32.dll是由两个函数入口的,一个是char型的一个是宽字符类型的通过一系列类似tcahr.h中的宏定义最终会自动选择调用哪个函数。 MessageBox函数定义如下: int WINAPI MessageBox (HWND, LPCSTR, LPCSTR, UINT) ;
函数的第二个、第三个参数是指向常数字符串的指针。而WINAPI它指定了一个呼叫约定,包括如何生产机械码以在堆栈中放置函数呼叫的参数。许多Windows函数呼叫声明为WINAPI。 下面是MessageBoxA在WINUSER.H中定义的方法。这与MessageBox早期的定义很相似:
下面是MessageBoxW:
WINUSERAPI int WINAPI MessageBoxW (HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType) ;在WINUSER.H中定义的相关宏
#ifdef UNICODE#define MessageBox MessageBoxW#else#define MessageBox MessageBoxA#endifNote: windwos 基本所有能自动识别char和宽字符的函数,底层都是通过上面的宏定义实现的。后缀A 表示的ASCII版本 ,也就是byte类型的。后缀W表示的是wide character 版本,也就是wchar_t。
windows 中字符处理的函数非常多,从所属版块我们可以大致分为三种。 - CRT,其中的很多函数只能处理char 或者宽字符字符串。且存在安全隐患。下面会详细介绍 - winows 同一编码维护的版本,这些能自动选择处理char还是宽字符字符串。也存在安全隐患 - windows 安全版。这些能自动选择处理char还是宽字符字符串。且不存在安全隐患
例如strlen 返回的是char(byte)的个数。而lstrlen会根据TCHAR具体的类型选择返回char长度还是宽字符个数。StringCchLength 也会根据TCHAR具体类型来返回char还是宽字符个数,但是这个函数会防止缓冲区溢出,而StringCbLength返回的是字符串中有多少个byte(1 char==1 byte,1 wchar_t==2 byte),同样这个函数一会防止缓冲区溢出。
而在CRT中字符处理方面的函数远不止上面那些。我也可以把它进行以下分类
c/c++标准中规定的函数。这些函数分为char 和宽字符版本。如strcat, wcscat, 非标准函数,以 _ 开头 如_mbscat,又可以分为下面几种 处理多字节字符集的函数。以_mbcs自动识别字符类型的函数,以_t开头,t表示TCHAR的意思。但是这些函数存在安全隐患。如_tprintf,_tcslen自动识别字符类型的函数,且不存在安全隐患的函数。以_s结尾, s表示secure, 如fprintf_s、_fprintf_s_l、fwprintf_s、_fwprintf_s_lTips: 详细的字符处理函数用法情参考msdn https://msdn.microsoft.com/en-us/library/windows/desktop/ff468909(v=vs.85).aspx
c标准中的printf(); int printf (const char * szFormat, …) ;· 而windows 中使用sprintf() int sprintf (char * szBuffer, const char * szFormat, …) ;
第一个参数是字符缓冲区;后面是一个格式字符串。Sprintf不是将格式化结果标准输出,而是将其存入szBuffer。该函数返回该字符串的长度。在文字模式程序设计中 printf (“The sum of %i and %i is %i”, 5, 3, 5+3) ; 的功能相同于 char szBuffer [100] ;
sprintf (szBuffer, “The sum of %i and %i is %i”, 5, 3, 5+3) ;
puts (szBuffer) ;
在Windows中,使用MessageBox显示结果优于puts。
几乎每个人都经历过,当格式字符串与被格式化的变量不合时,可能使printf执行错误并可能造成程序当掉。使用sprintf时,您不但要担心这些,而且还有一个新的负担:您定义的字符串缓冲区必须足够大以存放结果。Microsoft专用函数_snprintf解决了这一问题,此函数引进了另一个参数,表示以字符计算的缓冲区大小。
vsprintf是sprintf的一个变形,它只有三个参数。vsprintf用于执行有多个参数的自订函数,类似printf格式。vsprintf的前两个参数与sprintf相同:一个用于保存结果的字符缓冲区和一个格式字符串。第三个参数是指向格式化参数数组的指针。实际上,该指针指向在堆栈中供函数呼叫的变量。va_list、va_start和va_end宏(在STDARG.H中定义)帮助我们处理堆栈指针。本章最后的SCRNSIZE程序展示了使用这些宏的方法。使用vsprintf函数,sprintf函数可以这样编写:
int sprintf (char * szBuffer, const char * szFormat, …)
{
int iReturn ;va_list pArgs ;va_start (pArgs, szFormat) ;iReturn = vsprintf (szBuffer, szFormat, pArgs) ;va_end (pArgs) ;return iReturn ;}
va_start宏将pArg设置为指向一个堆栈变量,该变量地址在堆栈参数szFormat的上面。
由于许多Windows早期程序使用了sprintf和vsprintf,最终导致Microsoft向Windows API中增添了两个相似的函数。Windows的wsprintf和wvsprintf函数在功能上与sprintf和vsprintf相同,但它们不能处理浮点格式。
当然,随着宽字符的发表,sprintf类型的函数增加许多,使得函数名称变得极为混乱。表2-1列出了Microsoft的C执行时期链接库和Windows支持的所有sprintf函数。
ASCII | 宽字符 | 常规 | |
---|---|---|---|
参数的变数个数 | |||
标准版 | sprintf | swprintf | _stprintf |
最大长度版 | _snprintf | _snwprintf | _sntprintf |
windows版 | wsprintfA | wsprintfW | wsprintf |
参数数组的指针 | |||
标准版 | vsprintf | vswprintf | vstprintf |
最大长度版 | _vsnprintf | _vsnwprintf | _vsntprintf |
windwos版 | wvsprintfA | wvsprintfW | wvsprintf |
Tips: 详细的字符处理函数用法情参考msdn https://msdn.microsoft.com/en-us/library/windows/desktop/ff468909(v=vs.85).aspx
【参考】 winodws 程序设计 第五版
C/C++ Language and Standard Libraries https://msdn.microsoft.com/en-us/library/hh875057.aspx
Strings https://msdn.microsoft.com/en-us/library/windows/desktop/ms646979(v=vs.85).aspx
CRT Alphabetical Function Reference https://msdn.microsoft.com/en-us/library/634ca0c2.aspx
Tchar.h 中的一般文本映射 https://msdn.microsoft.com/zh-cn/library/c426s321.aspx
About Strings https://msdn.microsoft.com/en-us/library/windows/desktop/ms647465(v=vs.85).aspx
Unicode in Visual C++ 2 https://msdn.microsoft.com/en-us/library/cc194799.aspx
fprintf_s, _fprintf_s_l, fwprintf_s, _fwprintf_s_l https://msdn.microsoft.com/en-us/library/ksf1fzyy.aspx
通用 Windows 平台应用中不支持的 CRT 函数 https://msdn.microsoft.com/library/windows/apps/jj606124.aspx
[转]C++ Unicode SBCS 函数对照表 http://www.cnblogs.com/PiaoDbg/archive/2012/03/04/2379336.html
新闻热点
疑难解答