(精华版)_stprintf_s和_stscanf_s函数与UNICODE编码
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
版权所有。
转载请注明出处。
_stprintf_s和_stscanf_s函数与UNICODE编码
一、核心内容
⏹该文档适用于微软的visual C++ 平台。
⏹需要头文件:<TCHAR.H>
⏹MSDN上对stprintf_s和_stscanf_s函数的定义:
TCHAR.H routine _UNICODE & _MBCS not defined _MBCS defined _UNICODE defined
_stprintf_s sprintf_s sprintf_s swprintf_s
_stscanf_s sscanf_s sscanf_s swscanf_s
对应的代码为:
#ifdef UNICODE
#define _stprintf_s swprintf_s
#else
#define _stprintf_s sprintf_s
✓前面的t表示编码,后面的_s表示检查内存溢出,前面的_表示非标准库函数。
✓从上我们可以看出,_stprintf_s和_stscanf_s是为适应不同编码而定义的两个宏,在不同的编码环境下他们所表示的函数是不同的。
✓_s是security的意思,具体含义参见后面的Security Remarks部分。
(1)int sprintf_s( char *buffer, size_t sizeOfBuffer, const char *format [, argument] ... ); //ANSI版本
int swprintf_s(wchar_t *buffer, size_t sizeOfBuffer, const wchar_t *format [,argument]...); //UNICODE版本
这个函数的主要作用是将若干个argument按照format格式存到buffer中。
buffer:输出的字符
sizeOfBuffer:buffer的长度,以能存放的字符数计算,而不是已占用的字节数计算。
非常关键。
一个UNICODE字符占用2个字节。
format:格式字符串,比如%s
argument:可选参数
(2)int sscanf_s( const char *buffer, const char *format [, argument ] ... );
int swscanf_s( const wchar_t *buffer, const wchar_t *format [, argument ] ... );
函数具体细节参考/en-us/library/t6z7bya3(v=vs.80).aspx。
这个函数的主要作用是从buffer中读取指定格式(format)的字符到相应的argument中。
参数同上
Security Remarks:
Unlike the less secure version sscanf, a buffer size parameter sizeOfBuffer is required when using the type field characters c, C, s, S and [. This parameter must be supplied as an additional parameter after each buffer which requires it. 用于检查内存是否溢出。
几个需要注意的细节:
✓为了让编译器识别Unicode字符串,必须以在前面加一个“L”, 定义宽字节类型方法如下:L“ABC”,表示字符串“ABC”是用UNICODE编码的。
✓char与wchar_t的区别:char中存放的是单字节型的字符,wchar_t中存放的是双字节型的字符,TCHAR在定义了_UNICODE时等同于wchar_t,在未定义_UNICODE时等同于char。
例子1 (sscanf_s和printf_s,用于ANSI编码):
// crt_sscanf_s.c
// This program uses sscanf_s to read data items
// from a string named tokenstring, then displays them.
#include <stdio.h>
int main( void )
{
char tokenstring[] = "15 12 14...";
char s[81];
char c;
int i;
float fp;
// Input various data from tokenstring:
// max 80 character string plus NULL terminator
sscanf_s( tokenstring, "%s", s, sizeof(s) ); //对照上面的Security Remarks部分进行理解 sscanf_s( tokenstring, "%c", &c, sizeof(char) );
sscanf_s( tokenstring, "%d", &i );
sscanf_s( tokenstring, "%f", &fp );
// Output the data read
printf_s( "String = %s\n", s );
printf_s( "Character = %c\n", c );
printf_s( "Integer: = %d\n", i );
printf_s( "Real: = %f\n", fp );
return 0;
}
例子2 (swscanf_s和wprintf_s,用于UNICODE编码):
// crt_swscanf_s.c
// This program uses swscanf_s to read data items
// from a string named tokenstring, then displays them. #include <stdio.h>
int main( void )
{
wchar_t tokenstring[] = L"15 12 14...";
wchar_t s[81];
wchar_t c;
int i;
float fp;
// Input various data from tokenstring:
// max 80 character string plus NULL terminator
cout<<sizeof(wchar_t)<<" "<<_countof(s)<<endl;
swscanf_s( tokenstring, L"%s", s, _countof(s));
swscanf_s( tokenstring, L"%c", &c, sizeof(wchar_t) ); swscanf_s( tokenstring, L"%d", &i );
swscanf_s( tokenstring, L"%f", &fp );
// Output the data read
wprintf_s( L"String = %s\n", s );
wprintf_s( L"Character = %c\n", c );
wprintf_s( L"Integer: = %d\n", i );
wprintf_s( L"Real: = %f\n", fp );
return 0;
}
例子3 (_stscanf_s和_tprintf_s,将例1和例2的代码统一处理):#include <stdio.h>
int main( void )
{
TCHAR tokenstring[] = TEXT("15 12 14...");
TCHAR s[81];
TCHAR c;
int i;
float fp;
// Input various data from tokenstring:
// max 80 character string plus NULL terminator
cout<<sizeof(TCHAR)<<" "<<_countof(s)<<endl;
_stscanf_s( tokenstring, TEXT("%s"), s, _countof(s));
_stscanf_s( tokenstring, TEXT("%c"), &c, sizeof(TCHAR) );
_stscanf_s( tokenstring, TEXT("%d"), &i );
_stscanf_s( tokenstring, TEXT("%f"), &fp );
// Output the data read
_tprintf_s( TEXT("String = %s\n"), s );
_tprintf_s( TEXT("Character = %c\n"), c );
_tprintf_s( TEXT("Integer: = %d\n"), i );
_tprintf_s( TEXT("Real: = %f\n"), fp );
return 0;
}
例子4(_stprintf_s ):
TCHAR szText[32] = {0};
_stprintf_s(szText, 32,TEXT("%d"),100); // 可以将int 型转化为宽字节
同时也可以将若干个变量整合为一个
_stprintf_s(szText, 32,TEXT("%d"),char[0], char[1],.......);
用法总结:
1. 用TCHAR代替char
2. 用TEXT(“%s%d”)代替“%s%d”
3. 用_stscanf_s、_tprintf_s、_stprintf_s代替sscanf、printf、sprintf函数。
从而使程序能够在ANSI和UNICODE编码下都正确运行。
二、细节内容
1. %s %S %c %C 的区别。
参考/en-us/library/hf4y5e3w(VS.71).aspx
个人意见:尽量使用%s和%c,并统一使用TCHAR、TEXT和_stscanf_s、_tprintf_s、_stprintf_s类型的函数。
尽量不要使用%S和%C,容易引起混淆,可移植性也不好。
2. _TEXT(“”)、_T(“”)和TEXT(“”)的作用和区别。
_T("")是一个宏, 他的作用是让你的程序支持Unicode编码, 因为Windows使用两种字符集ANSI和UNICODE,前者就是通常使用的单字节方式,但这种方式处理象中文这样的双字节字符不方便,容易出现半个汉字的情况, 而后者是双字节方式,方便处理双字节字符。
_TEXT(“”)、_T(“”)和TEXT(“”)的作用是一样的。
3. _T和_L的区别。
_T和_L的区别在于,_L不管你是以什么方式编译,一律以UNICODE方式保存。
参考网页/14019890.html #ifdef UNICODE
#define __TEXT(quote) L##quote
#define __T(x) L##x
#else
#define __TEXT(quote) quote
#define __T(x) x
对于“#define __T(x) L##x”,这是相当晦涩的语法,但合乎ANSI C标准的前置处理器规范。
那一对井字号称为「粘贴符号(token paste)」,它将字母L 添加到宏参数上。
因此,如果宏参数是"Hello!",则L##x就是L"Hello!"。
三、扩展部分: Unicode与字符串处理函数
1. 通过对比学习“sprintf_s swprintf_s _stprintf_s ”和“sscanf_s swscanf_s _stscanf_s”,可以明白它们的区别。
还有很多与字符处理或字符串处理相关的函数,其形式和原理与之类似,可以对比学习和理解。
例如:strlen、wcslen和_tcslen函数(/zh-cn/library/78zh94ax(v=VS.80).aspx);fgets、fgetws与_fgetts函数
2. fgets、fgetws与_fgetts函数(/en-us/library/c37dh6kf(v=VS.71).aspx)
char * fgets ( char *string, int n, FILE *stream); //ANSI版本
wchar_t *fgetws( wchar_t *string, int n, FILE *stream); //UNICODE版本
✓其中,第二个参数n的值是最多可以读出的字符数目,该值不应该大于参数一所对应的字符数组的长度。
✓函数的作用是从第三个参数指定的文件流中读取文件的一行信息,存放到参数一string所对应的字符数组中,读出的字符数据包括换行符“\n”。
这一点需要注意。
✓如果想从键盘读入一行字符,第三个参数为stdin . 例如,char buf[10]; fgets(buf, 10, stdin) ;
✓gets()函数已经过时了,用fgets()函数代替gets()函数。
✓_fgetts是一个宏,如果定义了UNICODE,就是fgetws函数;如果未定义UNICODE,就是fgets函数。
✓用TCHAR代替char,用_fgetts代替fgets或fgetws。
就将ANSI和UNICODE函数编码统一起来了。
对这两个函数的更具体的讲解,请参考/view/d66839f57c1cfad6195fa781.html
3. ANSI和UNICODE字符和字符串处理函数,参考网页/s/blog_6b5a0745010108fh.html
统一ANSI和UNICODE字符和字符串处理函数的宏定义,在上述网页中没有列出,这些宏的规律是“把UNICODE字符和字符串处理函数中的w标
4. 注意:如果在程序中使用了TCHAR,那么就不应该使用ANSI的strXXX函数或者Unicode的wcsXXX函数了,而必须使用tchar.h中定义的_tcsXXX 函数。
5. 有人建议,不要再使用TCHAR和_T了!他分析了原因后总结:如果您正开始一个新的项目,请无论如何也要顶住压力,直接使用UNICODE编码!切记!您只需要对您的组员进行10分钟的培训,记住strcpy用wcscpy,sprintf用swprintf代替,常数前加L,就可以了!它不会花您很多时间的,带给您的是稳定和安全!个人觉得有道理。