VC的UNICODE 编程

简介

如果你编写的程序是针对非英语国家的用户,如中国、日本、东欧和中东地区,那么你一定要熟悉 UNICODE 字符集。尤其是用 Visual C++/MFC 编写针对上述国家和地区的用户的程序时,如果你想让自己的应用程序得到更广泛的用户,那么必须考虑代码 UNICODE 的兼容性,也就是说它既在 ASCII 模式下运行 ,也能在UNICODE 模式下运行。本文将介绍 UNICODE 的一些基本编程知识,澄清很多人(包括我自己)在这个问题上存在的模糊认识。对于任何使用 Visual C++ 和/或 MFC 编程的人来说,这篇文章肯定值得一读。

UNICODE到底是什么?

    UNICODE 是目前用来解决 ASCII 码 256 个字符限制问题的一种比较流行的解决方案。大家知道,ASCII 字符集只有256个字符,用 0-255 之间的数字来表示。包括大小写字母、数字以及少数特殊字符;如标点符号、货币符号等。对于大多数拉丁语言来说,这些字符已经够用。但是,许多亚洲和东方语言所用的字符远远不止256个字符。有些超过千个。人们为了突破 ASCII 码字符数的限制,试图用一种简单的方法来针对超过256个字符的语言编写计算机程序。于是 UNICODE 应运而生。UNICODE 通过用双字节来表示一个字符,从而在更大范围内将数字代码映射到多种语言的字符集。

Visual C++的解决方案

作为软件开发人员,如何熟练有效地使用 UNICODE 呢?如果你正在用 Visual C++ 编写程序,UNICODE 兼容性意味着你的程序是否具有国际化特征,也就是说你的应用程序是针对本地市场还是国际市场。一旦你作出了决定,那么就得在代码中实现具体细节。好在 Visual C++ 提供了很多内建功能来支持 UNICODE,在创建工程时就可以利用 Visual C++ 提供的这些功能。在产生应用程序框架代码之前,AppWizard 允许开发人员决定是否支持 UNICODE。Win32 SDK 包含有一些数据类型遵循 UNICODE 编码规则,MFC 以宏的形式提供了将一般文本转换成 UNICODE 数据类型的途径。开发人员只需要稍微改变一下编写代码的习惯便可以轻松编写支持 UNICODE 的应用。

字符串

C 程序员一般是用 char 关键字象下面这样来声明一个字符串数组:

       char str[100];       

象下面这样声明函数原形:

       void strcpy( char *out, char *in );        

为了将上面的声明改成支持双字节的 UNICODE 字符集,可以用下面的方法:

       wchar_t str[100];        

或者

       void wcscpy( wchar_t *out, wchar_t *in );        

此外,微软还提供一种通过预处理指令来实现 UNICODE。每当用 Visual C++ 创建新工程时,只要确定是否支持另外一种字符集,则 AppWizard 将会在头文件中插入预处理指令。这些指令告诉编译器程序想要支持何种字符集。这样在使用VC++提供的通用数据类型时,编译器将用相应的数据类型把通用数据类型替换成所需要支持的字符集。这样很容易将代码重新编译成支持其它字符集的程序。
    为了在 Visual C++ 6.0 中激活 UNICODE 标准,可以这样做:打开工程文件后,从主菜单中选择“Project | Settings”打开工程设置对话框 => 然后选择“C/C++”标签 => 在“Preprocessor definitions”编辑框中添加 UNICODE 或者 _UNICODE 预处理宏指令。如图一所示:

图一 Project Settings 对话框

注意这里的 UNICODE 和 _UNICODE 有什么区别呢?前者没有下划线,专门用于 Windows 头文件;后者有一个前缀下划线,专门用于 C 运行时头文件。
在代码中,凡是用关键字 char  的地方都用 TCHAR 取代;凡是用 char * 的地方都用 LPTSTR 取代;凡是定义在双引号中的字符串常量(如"VCKBASE Online Journal")都用 TEXT 宏重写:

       TEXT("VCKBASE Online Journal");       

TEXT 宏的主要作用是当定义了 UNICODE/_UNICODE 预处理指令时,字符串被标志为双字节字符串,否则字符串被标示为 ANSI 字符串。TEXT 的定义如下:

      TEXT(
           LPTSTR string // ANSI 或者 Unicode 字符串
      );
      参数   string 为字符串指针,指向被解释的 Unicode 或者 ANSI 字符串

在文档中 微软提供了包括通用类型在内的几种数据类型都与 ASCII 和 UNICODE兼容。这一点可以参考微软在线文档有关“通用数据类型和数据类型”的章节。

例子代码

下面通过一些简单的例子来进一步探讨 UNICODE 编程。

使用 ASCII 字符集的“Hello, World”:

//*********************************
// 用 MFC 实现的"Hello World!" 代码
//*********************************

//hello.cpp

#include <afxwin.h>

// Declare the application class
class CHelloApp : public CWinApp
{
public:
   virtual BOOL InitInstance();
};

// Create an instance of the application class
CHelloApp HelloApp;

// Declare the main window class
class CHelloWindow : public CFrameWnd
{
   CStatic* cs;
public:
   CHelloWindow();
};

// The InitInstance function is called each
// time the application first executes.
BOOL CHelloApp::InitInstance()
{
   m_pMainWnd = new CHelloWindow();
   m_pMainWnd->ShowWindow(m_nCmdShow);
   m_pMainWnd->UpdateWindow();
   return TRUE;
}

// The constructor for the window class
CHelloWindow::CHelloWindow()
{
   // Create the window itself
   Create(NULL, "Hello World!", WS_OVERLAPPEDWINDOW,
          CRect(0,0,200,200)); 

   // Create a static label
   cs = new CStatic();
   cs->Create("hello world", WS_CHILD|WS_VISIBLE|SS_CENTER,
              CRect(50,80,150,150), this);
}

修改上面的代码使之支持 UNICODE 字符集,串常量必须要改成对应的 UNICODE 字符。方法是对串常量使用TEXT 宏。这个宏将告诉预处理器检查使用什么样的字符标准:

// The constructor for the window class
CHelloWindow::CHelloWindow()
{
   // Create the window itself
   Create(NULL, TEXT("Hello World!"), WS_OVERLAPPEDWINDOW,
          CRect(0,0,200,200));

   // Create a static label
   cs = new CStatic();
   cs->Create( TEXT("hello world!"), WS_CHILD|WS_VISIBLE|SS_CENTER,
              CRect(50,80,150,150), this);
}

当预处理器碰到通用数据类型,它便检查 AFXWIN.H 头文件的 _UNICODE 定义。然后根据 UNICODE 定义插入相应的的数据类型。

下面的这个例子使用 Win32 API 函数和通用数据类型设置 C 盘的卷标。

//******************
// 设置 C 盘的卷标
//******************

// drvsvl.cpp

#include <windows.h>
#include <iostream.h>

void main()
{
   BOOL success;
   char volumeName[MAX_PATH];

   cout << "输入新的 C 盘卷标:";
   cin >> volumeName;

   success = SetVolumeLabel("c://", volumeName);
   if (success)
      cout << "成功/n";
   else
      cout << "错误代码:" << GetLastError() << endl;
}

通过使用 TCHAR 数据类型,将这段代码最上面的字符数组声明为两个字节的字符。TEXT 宏再次被用于字符串常量:

void main()
{
   BOOL success;

   TCHAR volumeName[MAX_PATH];

   cout << TEXT("输入新的 C 盘卷标: ");
   cin >> volumeName;

   success = SetVolumeLabel(TEXT("c://" ), volumeName);
   if (success)
      cout << TEXT("成功/n");
   else
      cout << TEXT("错误代码:") << GetLastError() << endl;
} 

Visual C++ 中的通用数据类型

Visual C++ 提供了几种 MFC 专用的数据类型用于创建具有国际化特性的应用程序。这些定义很通用,完全可以在 UNICODE、ASCII、DBCS (双字节字符集) 和 MBCS (多字节字符集)。由于篇幅所限,本文不打算涉及所有上面提到的这些字符集。有关它们的详细资料请参考相关资料。MFC 提供了一种透明的方式来实现这些字符集。通用数据类型的映射到哪个字符集以及映射方式是根据工程的设置决定的,默认值为 ASCII 模式,其它几个可选项是 MBCS、DBCS 或者 UNICODE。本文主要讨论 UNICODE,所以下表中只列出了 ASCII 与 UNICODE 字符之间的映射关系:

表一:

通用 MFC 数据类型 映射到 ASCII 映射到 UNICODE 注释
_TCHAR char wchar_t _TCHAR 是一个映射宏,当定义 UNICODE 时,该数据类型映射到 wchar_t,如果没有定义 UNICODE,那么它映射到 char。
_T 或 _TEXT char 常量字符串 wchar_t 常量字符串 功能与宏相同,在 ASCII 模式下,它们被忽略,也就是说被预处理器删除掉,但是如果定义了UNICODE, 则它们会将常量字符串转换成等价的 UNICODE 。
LPTSTR char*, LPSTR(Win32) wchar_t* 可移植的32位字符串指针。它将字符类型映射到工程设置的类型。
LPCTSTR const char*, LPCSTR(Win32) const wchar_t* 可移植的32位常量字符串指针。它将字符类型常量映射到工程设置的类型。

使用表一中列出的通用数据类型,开发人员可以保证所创建的工程始终是针对一种字符集,这些通用数据类型就相当于占位符,在编译时被特定的字节所替代,使得应用程序在 ASCII 和 UNICODE 模式下都能运行。但是,有一点要特别注意,那就是上述的通用数据类型为微软专有,与 ANSI 标准并不兼容。有关微软提供的这些通用数据类型详细描述请参考 MSDN 库文档。

有关技术注释

为了成功编译支持 UNICODE 的 MFC 程序,必须使用 MFC 的 UNICODE 版本库。该库在定制安装Visual C++ 时是个可选安装项。
    有一点很重要:那就是不使用 UNICODE 标准在外观上并不影响程序的执行。也就是说,上面提到过的代码不管设没设置 _UNICODE 生成选项,最终都能生成正常运行的程序。当开发人员使用多个版本的Win32 API函数时才会出现问题。
    在使用多个版本的 Win32 API函数(任何有字符或字符串作为参数的 Win32 API函数)时,编译器根据是否设置 _UNICODE 指令来决定调用正确的函数。如果没有定义_UNICODE,那么编译器将默认调用 ASCII 版本函数。

结束语

综上所述可以看到,编译 UNICODE 版本的程序并不难。只是在编写代码时记住函数调用上些微的变化。微软为此提供的扩展是开发人员能够以透明的方式选择所用的字符集,为应用软件的国际化打开了方便之门。
    Jeffrey Richter 在他的《Windows 核心编程》(机械工业出版社-王建华、张焕生、侯丽坤等译)一书中专门用一章讨论了 UNICODE。翻译得也不错。有兴趣的朋友不妨找来看看。

http://blog.csdn.net/yiruirui0507/article/details/6040601

时间: 2024-10-10 19:52:54

VC的UNICODE 编程的相关文章

VC++的Unicode编程

本文来自:http://tech.ddvip.com/2007-03/117395585321221.html 一.什么是Unicode 先从ASCII说起,ASCII是用来表示英文字符的一种编码规范.每个ASCII字符占用1个字节,因此,ASCII编码可以表示的最大字符数是255(00H—FFH).其实,英文字符并没有那么多,一般只用前128个(00H—7FH,最高位为0),其中包括了控制字符.数字.大小写字母和其它一些符号.而最高位为1的另128个字符(80H—FFH)被称为“扩展ASCII

【转】VC++的Unicode编程

转自http://www.cnblogs.com/kex1n/archive/2010/03/15/2286510.html 原始出处http://www.vckbase.com/document/viewdoc/?id=1733 一.什么是Unicode 先从ASCII说起,ASCII是用来表示英文字符的一种编码规范.每个ASCII字符占用1个字节,因此,ASCII编码可以表示的最大字符数是255(00H—FFH).其实,英文字符并没有那么多,一般只用前128个(00H—7FH,最高位为0),

【转】VC下的Unicode编程

转自http://www.leewei.org/?p=1304 UniCode简述 在Windows下用VC编程,如果编写的程序要在多种语言环境下运行(比如日文.中文.葡萄牙文等),使用VC默认的MBCS编译选项就会出现乱码,甚至导致程序崩溃.要克服这一缺点,就需要使用Unicode编程,简要说明一下Unicode: Unicode也是一种字符编码方法,它占用两个字节(0000H—FFFFH),容纳65536个字符,这完全可以容纳全世界所有语言文字的编码.在Unicode里,所有的文字都按一个字

VC++动态链接库(DLL)编程深入浅出(zz)

1.概论 先来阐述一下DLL(Dynamic Linkable Library)的概念,你可以简单的把DLL看成一种仓库,它提供给你一些可以直接拿来用的变量.函数或类.在仓库的发展史上经历了"无库-静态链接库-动态链接库"的时代. 静态链接库与动态链接库都是共享代码的方式,如果采用静态链接库,则无论你愿不愿意,lib中的指令都被直接包含在最终生成的EXE文件中了.但是若使用DLL,该DLL不必被包含在最终EXE文件中,EXE文件执行时可以"动态"地引用和卸载这个与E

【Windows编程】系列第四篇:使用Unicode编程

上一篇我们学习了Windows编程的文本及字体输出,在以上几篇的实例中也出现了一些带有“TEXT”的Windows宏定义,有朋友留言想了解一些ANSI和Unicode编程方面的内容,本章就来了解和学习一些Windows下关于ANSI和Unicode方面的编程基础. 计算机最早在美国诞生,所以最开始都是以英语为作为交互语言,由于只有26个字母,用一个字节(范围-128 ~ 127)表示,这个范围足够表示26个因为字符和一些常用的控制字符,这个就是ASCII编码.因此最早的各种程序设计语言以及使用的

VC++网络高级编程

内含<VC网络高级编程>电子书 及源码. 第一章.TCP/IP协议:第二章.Winsock网络编程接口:第二章.Visual C++与网络编程:第四章.基本网络编程技术:第五章.Telnet协议的实现:第六章.Http协议的实现:第七章.Ftp协议的实现:第八章.文件下载:第九章.UDP协议的实现: 下载地址:http://download.csdn.net/my VC++网络高级编程,布布扣,bubuko.com

VC++DUIEngine界面编程1--学习编译及配置DUIEngine项目

1. 为什么要用DUIEngine: DUIEngine的作者是:启程软件.在此感谢他为此项目所付出的心血,能为我们这些界面爱好者,奉献了宝贵的时间以及优秀的代码. DUIE的优势为: 1. 作者将金山的BKWin进行了深度改写,从而使之更易于使用和开发.相比传统的WTL而言,DUIE增加了许多窗口特效,如动态缩放窗口,3D界面旋转.从而使开发者能够在较短时间内开发出比较炫丽的界面特效. 2. 结合了MFC及WTL开发者的开发习惯,使开发者能够在较短时间内接受DUIE的开发模式. 3. 作者长时

【转】VC++消息钩子编程

VC++消息钩子编程

VC 中 字符串编程

/* #ifdef WIDECHAR//#ifdef  /#ifndef 具有在本文件内向上溯源性  在上面的可以识别  在下面的不能识别 #endif wchar_t *pszText=L"HelloT_char"; wprintf(L"%s\n",pszText); #else char *pszText="HelloT_char"; printf("单%s\n",pszText); #endif */ 对于wchar_t