Window编程常见数据类型及转换

window编程之数据数型

 

window编程中有两程编码格式,一种是MBCS 多字节字符集,另一种是UNICODE 字符集。

C++语言数据类型

C 语言

           1、常规基本类型   char int   float double  _bool _imaginary  _complex  _generic   (修饰为 short long  signed unsigned )  

            2、结构体类型 struct enum union    数组

            3、指针类型

            4、 NULL空类型

            也有把  NULL类型规入常规基本类型里面。

C++:    

             1、常规基本类型   char int   float double  _bool _imaginary  _complex  _generic   (修饰为 short long  signed unsigned )  bool类型

             2、结构体类型 struct enum union    数组 添加类(也有把它单独列为一列的)

             3、指针类型

             4、 NULL空类型

             也有把  NULL类型规入常规基本类型里面。

             C++另一种分 法为 1、基本数据类型  2、复合数据类型 3、指针类型 引用类型  4、NULL空类型

java: 数据类型:

             1、基本数据类型

             2、复合数据类型 (引用数据类型 )

                 (比C++新添加了) 接口 

              java 内存分配如下;                

                    ◆寄存器:我们在程序中无法控制

                    ◆栈:存放基本类型的数据和对象的引用,但对象本身不存放在栈中,而是存放在堆中

                    ◆堆:存放用new产生的数据

                    ◆静态域:存放在对象中用static定义的静态成员

                     ◆常量池:存放常量

                     ◆非RAM存储:硬盘等永久存储空间

 

               没有全局变量,自由存储区;

C#         

                1、基本类型 值类型

                2、 引用类型  包含指针

                3、 指针 也可独为一列

                C#只有堆栈 托管堆 三块内存空间

注: C标准库 和C++标准库也引入自定义的数据类弄    

 

Win32 常用数据类型

       Win32 API 自定义的一些数据数类型,在windows编程中广泛使用到。

以下这些数据类型被Win32 API支持可以用于定义函数返回值、函数和消息的参数或结构体成员变量.他们定义了相关数据大小和位。

下面这个表包含以下数据类型: 字符串、整型数、布尔型、指针类型和句柄类型.这些字符串、整型数、布尔型是同C编绎器公用的.大多的指针类型名称前缀使用 PLP.一个基本的Win32应用程序是使用一个句柄提交一个资源到内存中去的。

以下这些数据类型被Win32 API支持可以用于定义函数返回值、函数和消息的参数或结构体成员变量.他们定义了相关数据大小和位。

下面这个表包含以下数据类型: 字符串、整型数、布尔型、指针类型和句柄类型.这些字符串、整型数、布尔型是同C编绎器公用的.大多的指针类型名称前缀使用 PLP.一个基本的Win32应用程序是使用一个句柄提交一个资源到内存中去的。

 

类型

定义

ABORTPROC

指向一个应用程序定义的系统调用返回函数-当打印工作在假脱机期间被取消时的指针

ACMDRIVERENUMCB

指向一个程序定义调用返回函数-被acmDriverEnum使用.

ACMDRIVERPROC

指向一个程序定义调用返回函数-被一个安装音频压缩管理驱动器(ACM)

ACMFILTERCHOOSEHOOKPROC

指向一个程序定义函数-钩住acmFilterChoosec对话框

ACMFILTERENUMCB

指向一个程序定义调用返回函数被acmFilterEnum使用

ACMFILTERTAGENUMCB

指向一个程序定义调用返回函数被acmFilterTabEnum使用

ACMFORMATCHOOSEHOOKPROC

指向一个程序定义函数-钩住acmFormatChoose对话框

ACMFORMATENUMCB

指向一个程序定义调用返回函数被acmFormatEnum 使用

ACMFORMATTAGENUMCB

指向一个程序定义调用返回函数被acmFormatTagEnum 使用

APPLET_PROC

指向一个类库定义调用返回函数-在控制面板应用程序中为空指针

ATOM

Atom (参考字符串在一个atom表中).

BOOL

布尔类型值(应为 TRUE 或 FALSE).

BOOLEAN

布尔类型值(应为 TRUE 或 FALSE)..

BSTR

32bit字符指针类型

BYTE

字节类型 (8 bit).

CALINFO_ENUMPROC

指向一个程序定义调用返回函数收到一个日历信息字符串

CALLBACK

调用返回函数的调用习惯.

CHAR

8-位 Windows (ANSI)字符串

COLORREF

红, 绿, 蓝 (RGB)颜色值 (32位).

CONST

在运行期间保持不变的常量.

CRITICAL_SECTION

临界区对象.

CTRYID

国家标识符.

DATEFMT_ENUMPROC

指向一个程序定义调用返回函数收到一个日期格式的字符串

DESKTOPENUMPROC

指向一个程序定义调用返回函数收到一个桌面名称

DLGPROC

指向一个程序定义对话框返回程序

DRAWSTATEPROC

指向一个程序定义调用返回函数着色一个复合图象

DWORD

32-bit 无符号整数.

EDITWORDBREAKPROC

指向一个程序定义调用返回函数-当一个多行编辑控件需要文本换行时被操作系统调用.

ENHMFENUMPROC

指向一个程序定义调用返回函-列举增强图元文件记录

ENUMRESLANGPROC

指向一个程序定义调用返回函数-列举资源语言

ENUMRESNAMEPROC

指向一个程序定义调用返回函-列举一个资源名称

ENUMRESTYPEPROC

指向一个程序定义调用返回函-列举一个资源类型

FARPROC

指向一个程序定义调用返回函数.

FLOAT

浮点数类型.

FILE_SEGMENT_ELEMENT

64-bit 缓冲区指针

FONTENUMPROC

指向一个程序定义调用返回函数-列举字体

GOBJENUMPROC

指向一个程序定义调用返回函数列举图形设备对象 (GDI)

GRAYSTRINGPROC

指向一个程序定义调用返回函数-画灰色文本

HACCEL

加速键表句柄.

HANDLE

对象句柄

HBITMAP

位图句柄

HBRUSH

画刷句柄

HCOLORSPACE

逻辑颜色间隔句柄

HCONV

对态数据交换会话句柄(DDE)

HCONVLIST

DDE 会话列表句柄

HCURSOR

光标句柄.

HDC

设备上下文句柄(DC).

HDDEDATA

DDE数据句柄

HDESK

桌面句柄.

HDROP

内部结构体句柄.

HDWP

缓期窗口位置结构体句柄

HENHMETAFILE

增强图元文件句柄

HFILE

打开一个文件句柄(不是创建文件的句柄)

HFONT

字体句柄

HGDIOBJ

GDI对象句柄

HGLOBAL

全局大内存块句柄(连续内存).

HHOOK

钩子句柄

HICON

图标句柄

HIMAGELIST

图象列表对象句柄

HIMC

输入上下文句柄

HINSTANCE

实例句柄.

HKEY

注册键句柄

HKL

键盘规格句柄

HLOCAL

本地内存块句柄

HMENU

菜单句柄

HMETAFILE

图元文件句柄

HMODULE

模块句柄

HMONITOR

显示器句柄.

HOOKPROC

指向一个程序定义钩子函数被SetWindowsHookEx指定

HPALETTE

调色板句柄.

HPEN

画笔句柄

HRGN

区域句柄

HRSRC

资源句柄

HSZ

DDE串句柄.

HTREEITEM

树视控件节点条目句柄

HWINSTA

窗口位置句柄

HWND

窗口句柄

INT

有符号整数

IPADDR

IP 地址. 从一个IP地址转换到 "a.b.c.d" 形式

LANGID

语言标识符.

LCID

现场标识符

LCSCSTYPE

颜色间隔类型

LCSGAMUTMATCH

全音阶匹配模式

LCTYPE

现场消息类型

LINEDDAPROC

指向调用返回函数-进度条相配.

LOCALE_ENUMPROC

指向一个程序定义调用返回函数-收到一个现场标识串

LONG

32-bit 有符号长整数类型

LONGLONG

64-bit 有符号长整数类型.

LPARAM

32-bit消息参数(传到一个程序或从函数中返回)

LPBOOL

指向BOOL值的指针

LPBYTE

指向BYTE值的指针

LPCCHOOKPROC

指向一个程序钩子函数被颜色公共对话框使用.

LPCFHOOKPROC

指向一个程序钩子函数被字体公共对话框使用.

LPCOLORREF

指向一个COLORREF值的指针

LPCRECT

32bit不可变的矩形区域指针

LPCRITICAL_SECTION

指向临界区的指针.

LPCSTR

指向一个非终止常量8-bitWindows(ANSI)类型的字符串指针

LPCTSTR

若是UNICODE类型字符被定义同LPCWSTR,否则同LPCSTR

LPCVOID

指向一个任何类型的常量

LPCWSTR

指向一个非终止常量16-bitWindows(ANSI)类型的字符串

LPDWORD

指向DWORD类型值

LPFIBER_START_ROUTINE

指向一个光纤函数.

LPFRHOOKPROC

指向一个程序钩子函数被查找/替换公共对话框使用

LPHANDLE

指向一个HANDLE句柄的指针.

LPHANDLER_FUNCTION

指向一个控件句柄函数为Win32 服务器.

LPINT

指向一个INI类型值.

LPLONG

指向一个LONG类型值.

LPOFNHOOKPROC

指向一个程序钩子函数被打开和另存为公用对话框使用

LPPAGEPAINTHOOK

指向一个程序定义调用返回函数被页面设置公用对话框使用

LPPAGESETUPHOOK

指向一个程序定义调用返回函数被页面设置公用对话框使用

LPPRINTHOOKPROC

指向一个程序钩子函数被页面设置公用对话框使用

LPPROGRESS_ROUTINE

指向一个程序定义调用返回函数被CopyFileEx函数使用   

LPSETUPHOOKPROC

指向一个程序钩子函数被打印设置公用对话框使用

LPSTR

指向一个无终止符的8-bit Windows (ANSI)特征的字符串指针

LPSTREAM

指向一个流的指针

LPTHREAD_START_ROUTINE

指向一个线程函数的指针

LPTSTR

若UNICODE字符特征被定义同LPWSTR,否则同LPSTR.

LPVOID

指向任何类型值(32bit)

LPWORD

指向一个WORD类型值.

LPWSTR

指向一个无终止符的16-bit Windows (ANSI)特征的字符串

LRESULT

32bit返回指针值从一个Win程序或回调函数中

LUID

本地唯一的标识符

PBOOL

指向一个BOOL类型值.

PBOOLEAN

指向一个BOOL类型值

PBYTE

指向一个BYTE类型值.

PCHAR

指向一个CHAR类型值

PCRITICAL_SECTION

指向一个CRITICAL_SECTION类型值.

PCSTR

指向一个无终止符的8-bit Windows (ANSI)特征的常量字符串

PCTSTR

或是UNICODE类型字符被定义同PCWSTR,否则同PCSTR

PCWCH

指向一个常量WCHAR.

PCWSTR

指向一个无终止符16-bit Unicode特征的常量字符串

PDWORD

指向一个DWORD类型值.

PFLOAT

指向一个FLOAT类型的值

PFNCALLBACK

指向一个程序定义的回调函数-DDE处理指针

PHANDLE

指向一个HANDLE句柄类型值.

PHANDLER_ROUTINE

指向一个控制台程序句柄

PHKEY

指向一个HKEY类型值.

PINT

指向一个INT类型值

PLCID

指向一个LCID类型值

PLONG

指向一个LONG类型值

PLUID

指向一个LUID类型值

PROPENUMPROC

指向一个程序定义调用返回函数-列举窗口属性

PROPENUMPROCEX

指向一个程序定义调用返回函数- 列举窗口属性

PSHORT

指向一个SHORT类型值.

PSTR

指向一个无终止符的8-bit Windows (ANSI)特征字符串

PTBYTE

指向一个TBYTE类型的值

PTCHAR

指向一个TCHAR类型的值

PTIMERAPCROUTINE

指向一定时器完成程序

PTSTR

若是UNICODE被定义同PWSTR,否则同PSTR

PUCHAR

指向一个UCHAR类型的值.

PUINT

指向一个UINT类型的值

PULONG

指向一个ULONG类型的值

PUSHORT

指向一个UUSHORT类型的值.

PVOID

指向一个任何类型的值.

PWCHAR

指向一个UWCHAR类型的值

PWORD

指向一个UCHAR类型的值.Pointer to a WORD.

PWSTR

指向一个无终止符的16-bit Unicode特征字符串

REGISTERWORDENUMPROC

指向一个程序定义调用返回函数-处理注册字符串

REGSAM

为注册键设立的安全数据通路

SC_HANDLE

数据库管理控件句柄

SC_LOCK

数据库服务管理控件加锁句柄.

SENDASYNCPROC

指向一个程序定义调用返回函数-当操作系统调用SendMessageCallbace时

SERVICE_STATUS_HANDLE

服务器状态值句柄

SHORT

短整数类型.

TBYTE

若是UNICODE字符特征被定义同WCHAR,否则同CHAR.

TCHAR

若是UNICODE字符特征被定义同WCHAR,否则同CHAR..

TIMEFMT_ENUMPROC

指向一个程序定义调用返回函数-收到一个时间类型字符串

TIMERPROC

指向一个程序定义时间返回函数

UCHAR

无符号CHAR类型.

UINT

无符号INT类型.

ULONG

无符号LONG类型

ULONGLONG

64-bit 无符号整型数

UNSIGNED

无符号属性

USHORT

无符号SHORT类型

VOID

任何类型

WCHAR

16-bit Unicode类型字符.

WINAPI

Win32 API调用约定

WINSTAENUMPROC

指向一个程序定义调用返回函数-收到一个窗口位置名称t

WNDENUMPROC

指向一个程序定义调用返回函数-列举窗口

WNDPROC

指向一个windows程序指针

WORD

16-bit 无符号整数

WPARAM

32-bit 消息参数

YIELDPROC

指向一个回调函数

 

其它可用数据类型

 

类型

位数

其它名称

数值范围

__int8

1

char,
signed char

–128 到 127

__int16

2

short,
short int,
signed short int

–32,768 到 32,767

__int32

4

signed,
signed int

–2,147,483,648到 2,147,483,647

__int64

8

–9,223,372,036,854,775,808到

9,223,372,036,854,775,807

char

1

signed char

–128 到 127

unsigned char

1

0 到 255

short

2

short int,
signed short int

–32,768 到 32,767

unsigned short

2

unsigned short int

0 到 65,535

long

4

long int,
signed long int

–2,147,483,648 到 2,147,483,647

unsigned long

4

unsigned long int

0 到 4,294,967,295

enum

*

同 int

float

4

3.4E +/- 38 (7 digits)

double

8

1.7E +/- 308 (15 digits)

long double

10

1.2E +/- 4932 (19 digits)

 

 

 数据类型 说明
BOOL 布尔变量,实际上是UINT
COLORREF 用作颜色索引的32位整数
DWORD 32位的无符号整数
HANDLE 32位的无符号整数,用作句柄
HINSTANCE 32位的无符号整数,用作实例句柄
HWND 32位的无符号整数,用作窗口句柄
HDC 一个设备描述背景的句柄
LONG 32位带符号整数
LPARAM 32位整数,用作窗口函数或者其他回调函数的参数之一
LPCSTR 指向一个字符串常量的32位指针
LPSTR 定义一个线性的32位字符串指针
LRESULT 32位整数,是窗口函数或者其他回调函数的返回值类型
UINT 定义一个新的Win32数据类型,它会把一个参数强制转换成Windows3.x应用中的16位值 或Win32应用中的32位值
WCHAR 声明一个16位的UNICODE字符,用来表示世界上所有已知的书写语言的符号
WORD 16位的无符号整数
WPARAM 32位整数,用作窗口函数或者其他回调函数的参数之一(在Windows3.x中为16位值)


同时,为了统一变量的命名,在Windows中,不同类型的变量拥有各自的标准前缀,一般情况如表所示。
不同数据类型的前缀
前缀 数据类型
c 字符(char)
s 短整数(short)
cb 用于定义对象(一般为一个结构)尺寸的整数
n 整数(integer)
sz 以''结尾的字符串
b 字节
f BOOL
w 字(WORD,无符号短整数)
l 长整数(LONG)
h HANDLE(无符号整数)
m_ 类成员变量
fn 函数(function)
dw 双字(DWORD,无符号长整数)

MFC自定义数据类型

 Ctring

 

Com/DCOM /COM+  ATL /wtl 数据类型

BSTR

注:编码规范转换

 

1、windows 中的Unicode 定义

      WCHAR(Unicode字符)

      PWSTR(指向Unicode字符串的指针)

      PCWSTR(指向一个恒定的Unicode字符串的指针)

      C对UNICODE的支持

      比如常见函数:char *strchr(const char*,int) --------->wchar_t *wcschr(const wchar_t *,wchar_t);

                               int strcmp(const char*,const char*)-------->int wcscmp(const wchar_t*,const wchar_t*);

                               例如strcpy--->wcscpy,strlen->wcslen;实际是把wcs取代ANSI前缀str。

      C标准库中 string wstring  没有自适应类型

注:自适应类型只有MS自己出 L _T _Text(_TEXT 也就是_T)

2、ANSI/Unicode通用数据类型

      PTSTR和PCTSTR。

     Unicode 和ANSI相互转化

     char szA[100]; // An ANSI string buffer

     WCHAR szW[100];//A Unicode string buffer

     sprintf(szA,"%s","ANSI Str");            //Normal sprintf: all string are ANSI

     sprintf(szA,"%S",L"Unicode Str");   //Converts Unicode string to ANSI

     swprintf(szw,L"%S",L"Unicode Str");// Normal swprintf: all string are Unicode

     swprintf(szW,L"%S","ANSI Str");        // Converts ANSI string to Unicode     (严格注意大小写S)

     LPTSTR 等价于 char * 

     LPCSTR 等价于 const char *

     UNICODE和ANSI之间转化字符(函数参考MSDN)

     MultiByteToWideChar (多字节字符串转化为宽字节字符串)

     WideCharToMultiBye(宽字符串转为多字节字符串)

 

常用VC /VS下的数据类型转换

 

数据类型说明
BOOL布尔变量,实际上是UINT
COLORREF用作颜色索引的32位整数
DWORD32位的无符号整数
HANDLE32位的无符号整数,用作句柄
HINSTANCE32位的无符号整数,用作实例句柄
HWND32位的无符号整数,用作窗口句柄
HDC一个设备描述背景的句柄
LONG32位带符号整数
LPARAM32位整数,用作窗口函数或者其他回调函数的参数之一
LPCSTR指向一个字符串常量的32位指针
LPSTR定义一个线性的32位字符串指针
LRESULT32位整数,是窗口函数或者其他回调函数的返回值类型
UNIT

定义一个新的Win32数据类型,它会把一个参数强制转换成
Windows3.x应用中的16位值或Win32应用中的32位值

WCHAR声明一个16位的UNICODE字符,用来表示世界上所有已知
的书写语言的符号
WORD16位的无符号整数
WPARAM32位整数,用作窗口函数或者其他回调函数的参数之一
(在Windows3.x中为16位值)



C字符串转换[转]

一、BSTR、LPSTR和LPWSTR 
   在Visual C++.NET的所有编程方式中,我们常常要用到这样的一些基本字符串类型,如BSTR、LPSTR和LPWSTR等。之所以出现类似上述的这些数据类型,是因为不同编程语言之间的数据交换以及对ANSI、Unicode和多字节字符集(MBCS)的支持。

  那么什么是BSTR、LPSTR以及LPWSTR呢?

  BSTR(Basic STRing,Basic字符串)是一个OLECHAR*类型的Unicode字符串。它被描述成一个与自动化相兼容的类型。由于操作系统提供相应的API函数(如SysAllocString)来管理它以及一些默认的调度代码,因此BSTR实际上就是一个COM字符串,但它却在自动化技术以外的多种场合下得到广泛使用。图1描述了BSTR的结构,其中DWORD值是字符串中实际所占用的字节数,且它的值是字符串中 Unicode字符的两倍。

  LPSTR和LPWSTR是Win32和VC++所使用的一种字符串数据类型。LPSTR被定义成是一个指向以NULL(‘\0’)结尾的8位 ANSI字符数组指针,而LPWSTR是一个指向以NULL结尾的16位双字节字符数组指针。在VC++中,还有类似的字符串类型,如LPTSTR、 LPCTSTR等,它们的含义如图2所示。

  例如,LPCTSTR是指“long pointer to a constant generic string”,表示“一个指向一般字符串常量的长指针类型”,与C/C++的const char*相映射,而LPTSTR映射为 char*。

  一般地,还有下列类型定义:

#ifdef UNICODE 
  typedef LPWSTR LPTSTR;
  typedef LPCWSTR LPCTSTR; 
#else 
  typedef LPSTR LPTSTR; 
  typedef LPCSTR LPCTSTR; 
#endif

二、CString、CStringA 和 CStringW

  Visual C++.NET中将CStringT作为ATL和MFC的共享的“一般”字符串类,它有CString、CStringA和 CStringW三种形式,分别操作不同字符类型的字符串。这些字符类型是TCHAR、char和wchar_t。TCHAR在Unicode平台中等同于WCHAR(16位Unicode字符),在ANSI中等价于char。wchar_t通常定义为unsigned short。由于CString在 MFC应用程序中经常用到,这里不再重复。

三、VARIANT、COleVariant 和_variant_t

  在OLE、ActiveX和COM中,VARIANT数据类型提供了一种非常有效的机制,由于它既包含了数据本身,也包含了数据的类型,因而它可以实现各种不同的自动化数据的传输。下面让我们来看看OAIDL.H文件中VARIANT定义的一个简化版:

struct tagVARIANT {
  VARTYPE vt;
  union { 
   short iVal; // VT_I2. 
   long lVal; // VT_I4. 
   float fltVal; // VT_R4. 
   double dblVal; // VT_R8. 
   DATE date; // VT_DATE. 
   BSTR bstrVal; // VT_BSTR. 
   … 
   short * piVal; // VT_BYREF|VT_I2. 
   long * plVal; // VT_BYREF|VT_I4. 
   float * pfltVal; // VT_BYREF|VT_R4. 
   double * pdblVal; // VT_BYREF|VT_R8. 
   DATE * pdate; // VT_BYREF|VT_DATE. 
   BSTR * pbstrVal; // VT_BYREF|VT_BSTR. 
  }; 
}; 

  显然,VARIANT类型是一个C结构,它包含了一个类型成员vt、一些保留字节以及一个大的union类型。例如,如果vt为VT_I2,那么我们可以从iVal中读出VARIANT的值。同样,当给一个VARIANT变量赋值时,也要先指明其类型。例如:

VARIANT va;
:: VariantInit(&va); // 初始化
int a = 2002;
va.vt = VT_I4; // 指明long数据类型
va.lVal = a; // 赋值 

  为了方便处理VARIANT类型的变量,Windows还提供了这样一些非常有用的函数:

  VariantInit —— 将变量初始化为VT_EMPTY;

  VariantClear —— 消除并初始化VARIANT;

  VariantChangeType —— 改变VARIANT的类型;

  VariantCopy —— 释放与目标VARIANT相连的内存并复制源VARIANT。

  COleVariant类是对VARIANT结构的封装。它的构造函数具有极为强大大的功能,当对象构造时首先调用VariantInit进行初始化,然后根据参数中的标准类型调用相应的构造函数,并使用VariantCopy进行转换赋值操作,当VARIANT对象不在有效范围时,它的析构函数就会被自动调用,由于析构函数调用了VariantClear,因而相应的内存就会被自动清除。除此之外,COleVariant的赋值操作符在与 VARIANT类型转换中为我们提供极大的方便。例如下面的代码:

COleVariant v1("This is a test"); // 直接构造
COleVariant v2 = "This is a test"; 
// 结果是VT_BSTR类型,值为"This is a test"
COleVariant v3((long)2002);
COleVariant v4 = (long)2002;
// 结果是VT_I4类型,值为2002 

  _variant_t是一个用于COM的VARIANT类,它的功能与COleVariant相似。不过在Visual C++.NET的MFC应用程序中使用时需要在代码文件前面添加下列两句:

  #include "comutil.h"

  #pragma comment( lib, "comsupp.lib" )

四、CComBSTR和_bstr_t

  CComBSTR是对BSTR数据类型封装的一个ATL类,它的操作比较方便。例如:

CComBSTR bstr1; 
bstr1 = "Bye"; // 直接赋值
OLECHAR* str = OLESTR("ta ta"); // 长度为5的宽字符
CComBSTR bstr2(wcslen(str)); // 定义长度为5
wcscpy(bstr2.m_str, str); // 将宽字符串复制到BSTR中
CComBSTR bstr3(5, OLESTR("Hello World")); 
CComBSTR bstr4(5, "Hello World"); 
CComBSTR bstr5(OLESTR("Hey there")); 
CComBSTR bstr6("Hey there"); 
CComBSTR bstr7(bstr6); 
// 构造时复制,内容为"Hey there" 

  _bstr_t是是C++对BSTR的封装,它的构造和析构函数分别调用SysAllocString和SysFreeString函数,其他操作是借用BSTR API函数。与_variant_t相似,使用时也要添加comutil.h和comsupp.lib。

五、BSTR、char*和CString转换

  (1) char*转换成CString

  若将char*转换成CString,除了直接赋值外,还可使用CString::Format进行。例如:

char chArray[] = "This is a test";
char * p = "This is a test"; 

  或

LPSTR p = "This is a test"; 

  或在已定义Unicode应的用程序中

TCHAR * p = _T("This is a test"); 

  或

LPTSTR p = _T("This is a test");
CString theString = chArray;
theString.Format(_T("%s"), chArray);
theString = p; 

  (2) CString转换成char*

  若将CString类转换成char*(LPSTR)类型,常常使用下列三种方法:

  方法一,使用强制转换。例如:

CString theString( "This is a test" );
LPTSTR lpsz =(LPTSTR)(LPCTSTR)theString; 

  方法二,使用strcpy。例如:

CString theString( "This is a test" );
LPTSTR lpsz = new TCHAR[theString.GetLength()+1];
_tcscpy(lpsz, theString); 

  需要说明的是,strcpy(或可移值Unicode/MBCS的_tcscpy)的第二个参数是 const wchar_t* (Unicode)或const char* (ANSI),系统编译器将会自动对其进行转换。

  方法三,使用CString::GetBuffer。例如:

CString s(_T("This is a test "));
LPTSTR p = s.GetBuffer();
// 在这里添加使用p的代码
if(p != NULL) *p = _T('\0');
s.ReleaseBuffer(); 
// 使用完后及时释放,以便能使用其它的CString成员函数 

  (3) BSTR转换成char*

  方法一,使用ConvertBSTRToString。例如:

#include 
#pragma comment(lib, "comsupp.lib")
int _tmain(int argc, _TCHAR* argv[]){
BSTR bstrText = ::SysAllocString(L"Test");
char* lpszText2 = _com_util::ConvertBSTRToString(bstrText);
SysFreeString(bstrText); // 用完释放
delete[] lpszText2;
return 0;

  方法二,使用_bstr_t的赋值运算符重载。例如:

_bstr_t b = bstrText;
char* lpszText2 = b; 

  (4) char*转换成BSTR

  方法一,使用SysAllocString等API函数。例如:

BSTR bstrText = ::SysAllocString(L"Test");
BSTR bstrText = ::SysAllocStringLen(L"Test",4);
BSTR bstrText = ::SysAllocStringByteLen("Test",4); 

  方法二,使用COleVariant或_variant_t。例如:

//COleVariant strVar("This is a test");
_variant_t strVar("This is a test");
BSTR bstrText = strVar.bstrVal; 

  方法三,使用_bstr_t,这是一种最简单的方法。例如:

BSTR bstrText = _bstr_t("This is a test"); 

  方法四,使用CComBSTR。例如:

BSTR bstrText = CComBSTR("This is a test"); 

  或

CComBSTR bstr("This is a test");
BSTR bstrText = bstr.m_str; 

  方法五,使用ConvertStringToBSTR。例如:

char* lpszText = "Test";
BSTR bstrText = _com_util::ConvertStringToBSTR(lpszText); 

  (5) CString转换成BSTR

  通常是通过使用CStringT::AllocSysString来实现。例如:

CString str("This is a test");
BSTR bstrText = str.AllocSysString();

SysFreeString(bstrText); // 用完释放 

  (6) BSTR转换成CString

  一般可按下列方法进行:

BSTR bstrText = ::SysAllocString(L"Test");
CStringA str;
str.Empty();
str = bstrText; 

  或

CStringA str(bstrText); 

  (7) ANSI、Unicode和宽字符之间的转换

  方法一,使用MultiByteToWideChar将ANSI字符转换成Unicode字符,使用WideCharToMultiByte将Unicode字符转换成ANSI字符。

  方法二,使用“_T”将ANSI转换成“一般”类型字符串,使用“L”将ANSI转换成Unicode,而在托管C++环境中还可使用S将ANSI字符串转换成String*对象。例如:

TCHAR tstr[] = _T("this is a test");
wchar_t wszStr[] = L"This is a test";
String* str = S”This is a test”; 

  方法三,使用ATL 7.0的转换宏和类。ATL7.0在原有3.0基础上完善和增加了许多字符串转换宏以及提供相应的类,它具有如图3所示的统一形式:

  其中,第一个C表示“类”,以便于ATL 3.0宏相区别,第二个C表示常量,2表示“to”,EX表示要开辟一定大小的缓冲。SourceType 和DestinationType可以是A、T、W和OLE,其含义分别是ANSI、Unicode、“一般”类型和OLE字符串。例如,CA2CT就是将ANSI转换成一般类型的字符串常量。下面是一些示例代码:

LPTSTR tstr= CA2TEX<16>("this is a test");
LPCTSTR tcstr= CA2CT("this is a test");
wchar_t wszStr[] = L"This is a test";
char* chstr = CW2A(wszStr); 

///


VC常用数据类型使用转换详解


刚接触VC编程的朋友往往对许多数据类型的转换感到迷惑不解,本文将介绍一些常用数据类型的使用。

我们先定义一些常见类型变量借以说明

int i = 100;
long l = 2001;
float f=300.2;
double d=12345.119;
char username[]="赵三";
char temp[200];
char *buf;
CString str;
_variant_t v1;
_bstr_t v2;

一、其它数据类型转换为字符串


短整型(int)
itoa(i,temp,10);///将i转换为字符串放入temp中,最后一个数字表示十进制
itoa(i,temp,2); ///按二进制方式转换 
长整型(long)
ltoa(l,temp,10); 
浮点数(float,double)
用fcvt可以完成转换,这是MSDN中的例子:
int decimal, sign; 
char *buffer; 
double source = 3.1415926535; 
buffer = _fcvt( source, 7, &decimal, &sign ); 
运行结果:source: 3.1415926535 buffer: '31415927' decimal: 1 sign: 0
decimal表示小数点的位置,sign表示符号:0为正数,1为负数 
CString变量
str = "2008北京奥运";
buf = (LPSTR)(LPCTSTR)str; 
BSTR变量
BSTR bstrValue = ::SysAllocString(L"程序员"); 
char * buf = _com_util::ConvertBSTRToString(bstrValue); 
SysFreeString(bstrValue); 
AfxMessageBox(buf); 
delete(buf); 
CComBSTR变量
CComBSTR bstrVar("test"); 
char *buf = _com_util::ConvertBSTRToString(bstrVar.m_str); 
AfxMessageBox(buf); 
delete(buf); 

_bstr_t变量
_bstr_t类型是对BSTR的封装,因为已经重载了=操作符,所以很容易使用
_bstr_t bstrVar("test"); 
const char *buf = bstrVar;///不要修改buf中的内容 
AfxMessageBox(buf); 


通用方法(针对非COM数据类型)
用sprintf完成转换
char  buffer[200];
char  c = '1';
int   i = 35;
long  j = 1000;
float f = 1.7320534f;
sprintf( buffer, "%c",c);
sprintf( buffer, "%d",i);
sprintf( buffer, "%d",j);
sprintf( buffer, "%f",f);

二、字符串转换为其它数据类型
strcpy(temp,"123"); 

短整型(int)
i = atoi(temp); 
长整型(long)
l = atol(temp); 
浮点(double)
d = atof(temp); 
CString变量
CString name = temp; 
BSTR变量 
BSTR bstrValue = ::SysAllocString(L"程序员"); 
...///完成对bstrValue的使用
SysFreeString(bstrValue); 

CComBSTR变量
CComBSTR类型变量可以直接赋值
CComBSTR bstrVar1("test");
CComBSTR bstrVar2(temp);

_bstr_t变量
_bstr_t类型的变量可以直接赋值
_bstr_t bstrVar1("test"); 
_bstr_t bstrVar2(temp); 

三 
、其它数据类型转换到CString
使用CString的成员函数Format来转换,例如:


整数(int)
str.Format("%d",i); 
浮点数(float)
str.Format("%f",i); 
字符串指针(char *)等已经被CString构造函数支持的数据类型可以直接赋值
str = username; 
对于Format所不支持的数据类型,可以通过上面所说的关于其它数据类型转化到char *的方法先转到char *,然后赋值给CString变量。

四、BSTR、_bstr_t与CComBSTR


CComBSTR 是ATL对BSTR的封装,_bstr_t是C++对BSTR的封装,BSTR是32位指针,但并不直接指向字串的缓冲区。
char *转换到BSTR可以这样: 
BSTR b=_com_util::ConvertStringToBSTR("数据");///使用前需要加上comutil.h和comsupp.lib
SysFreeString(bstrValue); 
反之可以使用
char *p=_com_util::ConvertBSTRToString(b);
delete p;
具体可以参考一,二段落里的具体说明。

CComBSTR与_bstr_t对大量的操作符进行了重载,可以直接进行=,!=,==等操作,所以使用非常方便。
特别是_bstr_t,建议大家使用它。


五、VARIANT 、_variant_t 与 COleVariant

VARIANT的结构可以参考头文件VC98\Include\OAIDL.H中关于结构体tagVARIANT的定义。
对于VARIANT变量的赋值:首先给vt成员赋值,指明数据类型,再对联合结构中相同数据类型的变量赋值,举个例子:
VARIANT va;
int a=2001;
va.vt=VT_I4;///指明整型数据
va.lVal=a; ///赋值

对于不马上赋值的VARIANT,最好先用Void VariantInit(VARIANTARG FAR* pvarg);进行初始化,其本质是将vt设置为VT_EMPTY,下表我们列举vt与常用数据的对应关系:

Byte bVal;  // VT_UI1. 
Short iVal;  // VT_I2. 
long lVal;  // VT_I4. 
float fltVal;  // VT_R4. 
double dblVal;  // VT_R8. 
VARIANT_BOOL boolVal;  // VT_BOOL. 
SCODE scode;  // VT_ERROR. 
CY cyVal;  // VT_CY. 
DATE date;  // VT_DATE. 
BSTR bstrVal;  // VT_BSTR. 
DECIMAL FAR* pdecVal  // VT_BYREF|VT_DECIMAL. 
IUnknown FAR* punkVal;  // VT_UNKNOWN. 
IDispatch FAR* pdispVal;  // VT_DISPATCH. 
SAFEARRAY FAR* parray;  // VT_ARRAY|*. 
Byte FAR* PBVal;  // VT_BYREF|VT_UI1. 
short FAR* piVal;  // VT_BYREF|VT_I2. 
long FAR* plVal;  // VT_BYREF|VT_I4. 
float FAR* pfltVal;  // VT_BYREF|VT_R4. 
double FAR* pdblVal;  // VT_BYREF|VT_R8. 
VARIANT_BOOL FAR* pboolVal;  // VT_BYREF|VT_BOOL. 
SCODE FAR* pscode;  // VT_BYREF|VT_ERROR. 
CY FAR* pcyVal;  // VT_BYREF|VT_CY. 
DATE FAR* pdate;  // VT_BYREF|VT_DATE. 
BSTR FAR* pbstrVal;  // VT_BYREF|VT_BSTR. 
IUnknown FAR* FAR* ppunkVal;  // VT_BYREF|VT_UNKNOWN. 
IDispatch FAR* FAR* ppdispVal;  // VT_BYREF|VT_DISPATCH. 
SAFEARRAY FAR* FAR* pparray;  // VT_ARRAY|*. 
VARIANT FAR* pvarVal;  // VT_BYREF|VT_VARIANT. 
void FAR* byref;  // Generic ByRef. 
char cVal;  // VT_I1. 
unsigned short uiVal;  // VT_UI2. 
unsigned long ulVal;  // VT_UI4. 
int intVal;  // VT_INT. 
unsigned int uintVal;  // VT_UINT. 
char FAR * pcVal;  // VT_BYREF|VT_I1. 
unsigned short FAR * puiVal;  // VT_BYREF|VT_UI2. 
unsigned long FAR * pulVal;  // VT_BYREF|VT_UI4. 
int FAR * pintVal;  // VT_BYREF|VT_INT. 
unsigned int FAR * puintVal;  //VT_BYREF|VT_UINT. 


_variant_t是VARIANT的封装类,其赋值可以使用强制类型转换,其构造函数会自动处理这些数据类型。
使用时需加上#include <comdef.h>
例如:
long l=222;
ing i=100;
_variant_t lVal(l);
lVal = (long)i;


COleVariant的使用与_variant_t的方法基本一样,请参考如下例子:
COleVariant v3 = "字符串", v4 = (long)1999;
CString str =(BSTR)v3.pbstrVal;
long i = v4.lVal;


六、其它一些COM数据类型

根据ProgID得到CLSID
HRESULT CLSIDFromProgID( LPCOLESTR lpszProgID,LPCLSID pclsid);
CLSID clsid;
CLSIDFromProgID( L"MAPI.Folder",&clsid);

根据CLSID得到ProgID
WINOLEAPI ProgIDFromCLSID( REFCLSID clsid,LPOLESTR * lplpszProgID); 
例如我们已经定义了 CLSID_IApplication,下面的代码得到ProgID
LPOLESTR pProgID = 0;
ProgIDFromCLSID( CLSID_IApplication,&pProgID);
...///可以使用pProgID 
CoTaskMemFree(pProgID);//不要忘记释放 

七、ANSI与Unicode
Unicode称为宽字符型字串,COM里使用的都是Unicode字符串。

将ANSI转换到Unicode
(1)通过L这个宏来实现,例如: CLSIDFromProgID( L"MAPI.Folder",&clsid);
(2)通过MultiByteToWideChar函数实现转换,例如:
char *szProgID = "MAPI.Folder";
WCHAR szWideProgID[128];
CLSID clsid;
long lLen = MultiByteToWideChar(CP_ACP,0,szProgID,strlen(szProgID),szWideProgID,sizeof(szWideProgID));
szWideProgID[lLen] = '\0'; 
(3)通过A2W宏来实现,例如: 
USES_CONVERSION; 
CLSIDFromProgID( A2W(szProgID),&clsid); 
将Unicode转换到ANSI
(1)使用WideCharToMultiByte,例如:
// 假设已经有了一个Unicode 串 wszSomeString... 
char szANSIString [MAX_PATH]; 
WideCharToMultiByte ( CP_ACP, WC_COMPOSITECHECK, wszSomeString, -1, szANSIString, sizeof(szANSIString), NULL, NULL ); 
(2)使用W2A宏来实现,例如:
USES_CONVERSION;
pTemp=W2A(wszSomeString); 
八、其它

对消息的处理中我们经常需要将WPARAM或LPARAM等32位数据(DWORD)分解成两个16位数据(WORD),例如:
LPARAM lParam;
WORD loValue = LOWORD(lParam);///取低16位
WORD hiValue = HIWORD(lParam);///取高16位


对于16位的数据(WORD)我们可以用同样的方法分解成高低两个8位数据(BYTE),例如:
WORD wValue;
BYTE loValue = LOBYTE(wValue);///取低8位
BYTE hiValue = HIBYTE(wValue);///取高8位


两个16位数据(WORD)合成32位数据(DWORD,LRESULT,LPARAM,或WPARAM)
LONG MAKELONG( WORD wLow, WORD wHigh );
WPARAM MAKEWPARAM( WORD wLow, WORD wHigh ); 
LPARAM MAKELPARAM( WORD wLow, WORD wHigh );
LRESULT MAKELRESULT( WORD wLow, WORD wHigh ); 


两个8位的数据(BYTE)合成16位的数据(WORD)
WORD MAKEWORD( BYTE bLow, BYTE bHigh ); 


从R(red),G(green),B(blue)三色得到COLORREF类型的颜色值
COLORREF RGB( BYTE byRed,BYTE byGreen,BYTE byBlue );
例如COLORREF bkcolor = RGB(0x22,0x98,0x34);


从COLORREF类型的颜色值得到RGB三个颜色值
BYTE Red = GetRValue(bkcolor); ///得到红颜色
BYTE Green = GetGValue(bkcolor); ///得到绿颜色
BYTE Blue = GetBValue(bkcolor); ///得到兰颜色


九、注意事项
假如需要使用到ConvertBSTRToString此类函数,需要加上头文件comutil.h,并在setting中加入comsupp.lib或者直接加上#pragma comment( lib, "comsupp.lib" )


CString怎么和其他类型转换?
zyca (天行健者)     2004-03-31 02:08:57 在 VC/MFC / 基础类 提问
CString   number("123");   
  如何把它变成int 

问题点数:20、回复次数:9 

1楼  bm1408   (要向宁五爷学啊~~要向宁五爷学啊!~)   回复于 2004-03-31 02:14:24  得分 10 
CString、char*、string、int、_bstr_t、CTime、COleDateTime等等的相互转换,如何判断一个字符串是一个浮点数?   
    
  #include<string>   
  using   namespace   std;   
  #include   <COMDEF.H>   
  {   
  CString   strCString="ABC";   
  char   strchar[256],*pstr;   
    
  pstr=(LPSTR)(LPCTSTR)strCString;   //CString---->char*   
  strcpy(strchar,(LPSTR)(LPCTSTR)strCString);   //CString---->char[]   
    
  _bstr_t   strbstr=pstr;   //char*---->_bstr_t   
  WCHAR   *strWCHAR=strbstr;   //b_str_t--->UNICODE   
    
  strbstr=strWCHAR;   
  pstr=strbstr;   //UNICODE---->char*   
    
  strCString="10";   
  int   istr=atoi((LPSTR)(LPCTSTR)strCString);   //CString、char[]、char*------>int   
  strCString.Format("%d",istr);   //int----->CString   
  sprintf(strchar,"%d",istr);   //int----->char[]   
    
  pstr=new   char[256];   //字符串申请空间   
  strcpy(pstr,"ABC");   //字符串赋值   
  delete   []pstr;   //字符串释放   
    
  string   strstring="ABC";   
  pstr=(char*)strstring.c_str();   //string---->char*   
    
  strCString="2003-10-27   6:24:37";   //CString--->COleDateTime   
  COleVariant   vtime(strCString);   
  vtime.ChangeType(VT_DATE);   
  COleDateTime   time4=vtime;   
    
  COleDateTime   time1(1977,4,16,2,2,2);   //COleDataTime--->CTime   
  SYSTEMTIME   systime;   
  VariantTimeToSystemTime(time1,   &systime);   
  CTime   tm(systime);   
    
  time_t   time2=tm.GetTime();   //CTime--->time_t   
  COleDateTime   time3(time2);   //time_t--->COleDateTime   
    
  //判断字符串是否是某种类型   
  CString   sValue("123.1");   
  COleVariant   vValue(sValue);   
    
  BOOL   bStrIsFloat   =   (SUCCEEDED(VariantChangeType(&vValue,   &vValue,   0,   VT_R8))   &&   sValue.Find('.')   !=   -1);   
  if(bStrIsFloat)   
  {   
  AfxMessageBox("浮点");   
  }   
  }       
  

Top
2楼  bluebohe   (薄荷)   回复于 2004-03-31 02:18:16  得分 4 
int   a=atoi(number); 


关于CString总结   
    
  前言:串操作是编程中最常用也最基本的操作之一.   做为VC程序员,无论是菜鸟或高手都曾用   
  过CString.而且好像实际编程中很难离得开它(虽然它不是标准C++中的库).因为MFC中提   
  供的这个类对我们操作字串实在太方便了,CString不仅提供各种丰富的操作函数、操作符重   
  载,使我们使用起串起来更象basic中那样直观;而且它还提供了动态内存分配,使我们减   
  少了多少字符串数组越界的隐患。但是,我们在使用过程中也体会到CString简直太容易出   
  错了,而且有的不可捉摸。所以有许多高人站过来,建议抛弃它。   
          在此,我个人认为:CString封装得确实很完美,它有许多优点,如“容易使用   ,功能   
  强,动态分配内存,大量进行拷贝时它很能节省内存资源并且执行效率高,与标准C完全兼   
  容,同时支持多字节与宽字节,由于有异常机制所以使用它安全方便”   其实,使用过程中   
  之所以容易出错,那是因为我们对它了解得还不够,特别是它的实现机制。因为我们中的大   
  多数人,在工作中并不爱那么深入地去看关于它的文档,何况它还是英文的。     
        由于前几天我在工作中遇到了一个本不是问题但却特别棘手、特别难解决而且莫名惊诧   
  的问题。最后发现是由于CString引发的,后来,没办法,我把整个CString的实现全部看了   
  一遍,才慌然大悟,并彻底弄清了问题的原因(这个问题,我已在csdn上开贴)。在此,我想   
  把我的一些关于CString的知识总结一番,以供他(她)人借鉴,也许其中有我理解上的错   
  误,望发现者能通知我,不胜感谢。   
    
  1   CString实现的机制.   
        CString是通过“引用”来管理串的,“引用”这个词我相信大家并不陌生,象Window内   
  核对象、COM对象等都是通过引用来实现的。而CString也是通过这样的机制来管理分配的内   
  存块。实际上CString对象只有一个指针成员变量,所以任何CString实例的长度只有4字节.   
                即:   int   len   =   sizeof(CString);//len等于4   
  这个指针指向一个相关的引用内存块,如图:   CString   str("abcd");   
                                                                                          ___   
            ____________                                                     |       |     
          |                         |                                                   |       |     
          |   0x04040404   |                                                   |       |     head部,为引用内存块相关信息   
          |____________|                                                   |       |   
                    str                                                               |___|   
                                                                                        |'a'|   0x40404040   
                                                                                        |'b'|   
                                                                                        |'c'|   
                                                                                        |'d'|   
                                                                                        |   0   |   
    
  正因为如此,一个这样的内存块可被多个CString所引用,例如下列代码:   
  CString   str("abcd");   
  CString   a   =   str;   
  CString   b(str);   
  CString   c;   
  c   =   b;   
  上面代码的结果是:上面四个对象(str,a,b,c)中的成员变量指针有相同的值,都为   
  0x40404040.而这块内存块怎么知道有多少个CString引用它呢?同样,它也会记录一些信   
  息。如被引用数,串长度,分配内存长度。   
  这块引用内存块的结构定义如下:   
  struct   CStringData   
  {   
      long   nRefs;               //表示有多少个CString   引用它.   4   
      int   nDataLength;     //串实际长度.   4   
      int   nAllocLength;   //总共分配的内存长度(不计这头部的12字节).   4   
  };   
  由于有了这些信息,CString就能正确地分配、管理、释放引用内存块。   
  如果你想在调试程序的时候获得这些信息。可以在Watch窗口键入下列表达式:   
  (CStringData*)((CStringData*)(this->m_pchData)-1)或   
  (CStringData*)((CStringData*)(str.m_pchData)-1)//str为指CString实例   
    
  正因为采用了这样的好机制,使得CString在大量拷贝时,不仅效率高,而且分配内存少。   
    
  2   LPCTSTR   与   GetBuffer(int   nMinBufLength)     
  这两个函数提供了与标准C的兼容转换。在实际中使用频率很高,但却是最容易出错的地   
  方。这两个函数实际上返回的都是指针,但它们有何区别呢?以及调用它们后,幕后是做了   
  怎样的处理过程呢?   
      (1)   LPCTSTR   它的执行过程其实很简单,只是返回引用内存块的串地址。   它是作为操作   
  符重载提供的,   
              所以在代码中有时可以隐式转换,而有时却需强制转制。如:   
                      CString   str;   
                      const   char*   p   =   (LPCTSTR)str;   
                      //假设有这样的一个函数,Test(const   char*   p);     你就可以这样调用   
                      Test(str);//这里会隐式转换为LPCTSTR   
      (2)   GetBuffer(int   nMinBufLength)   它类似,也会返回一个指针,不过它有点差别,返回   
  的是LPTSTR   
      (3)   这两者到底有何不同呢?我想告诉大家,其本质上完全不一样,一般说LPCTSTR转换   
  后只应该当常量使用,或者做函数的入参;而GetBuffer(...)取出指针后,可以通过这个指   
  针来修改里面的内容,或者做函数的入参。为什么呢?也许经常有这样的代码:   
                  CString   str("abcd");   
                  char*   p   =   (char*)(const   char*)str;   
                  p[2]   =   'z';         
              其实,也许有这样的代码后,你的程序并没有错,而且程序也运行得挺好。但它却是   
  非常危险的。再看   
                  CString   str("abcd");   
                  CString   test   =   str;   
                  ....   
                  char*   p   =   (char*)(const   char*)str;   
                  p[2]   =   'z';         
                  strcpy(p,   "akfjaksjfakfakfakj");//这下完蛋了         
              你知道此时,test中的值是多少吗?答案是"abzd".它也跟着改变了,这不是你所期   
  望发生的。但为什么会这样呢?你稍微想想就会明白,前面说过,因为CString是指向引用   
  块的,str与test指向同一块地方,当你p[2]='z'后,当然test也会随着改变。所以用它做   
  LPCTSTR做转换后,你只能去读这块数据,千万别去改变它的内容。   
                
              假如我想直接通过指针去修改数据的话,那怎样办呢?就是用GetBuffer(...).看下   
  述代码:   
                  CString   str("abcd");   
                  CString   test   =   str;   
                  ....   
                  char*   p   =   str.GetBuffer(20);   
                  p[2]   =   'z';     //       执行到此,现在test中值却仍是"abcd"   
                  strcpy(p,   "akfjaksjfakfakfakj");       //         执行到此,现在test中值还是   
  "abcd"   
              为什么会这样?其实GetBuffer(20)调用时,它实际上另外建立了一块新内块存,并   
  分配20字节长度的buffer,而原来的内存块引用计数也相应减1.     所以执行代码后str与test   
  是指向了两块不同的地方,所以相安无事。
    
  (4)   不过这里还有一点注意事项:就是str.GetBuffer(20)后,str的分配长度为20,即指针   
  p它所指向的buffer只有20字节长,给它赋值时,切不可超过,否则灾难离你不远了;如果   
  指定长度小于原来串长度,如GetBuffer(1),实际上它会分配4个字节长度(即原来串长度)   
  ;另外,当调用GetBuffer(...)后并改变其内容,一定要记得调用ReleaseBuffer(),这个函   
  数会根据串内容来更新引用内存块的头部信息。   
        (5)   最后还有一注意事项,看下述代码:   
              char*   p   =   NULL;   
              const   char*   q   =   NULL;   
              {   
                      CString   str   =   "abcd";   
                      q   =   (LPCTSTR)str;   
                      p   =   str.GetBuffer(20);   
                      AfxMessageBox(q);//   合法的   
                      strcpy(p,   "this   is   test");//合法的,   
              }   
              AfxMessageBox(q);//   非法的,可能完蛋   
              strcpy(p,   "this   is   test");//非法的,可能完蛋   
              这里要说的就是,当返回这些指针后,   如果CString对象生命结束,这些指针也相应   
  无效。   
    
    
    
  下面演示一段代码执行过程   
        void   Test()   
        {   
            CString   str("abcd");//str指向一引用内存块(引用内存块的引用计数为1,   
                                                        长度为4,分配长度为4)   
            CString   a;//a指向一初始数据状态,   
            a   =   str;     //a与str指向同一引用内存块(引用内存块的引用计数为2,   
                                      长度为4,分配长度为4)   
            CString   b(a);//a、b与str指向同一引用内存块(引用内存块的引用   
                                        计数为3,长度为4,分配长度为4)   
            {   
                  LPCTSTR   temp   =   (LPCTSTR)a;//temp指向引用内存块的串首地址。   
                                                                      (引用内存块的引用计数为3,长度为4,分配长度为4   
  )   
                  CString   d   =   a;   //a、b、d与str指向同一引用内存块(引用内存块的引用计数为   
  4,                                                                 长度为4,分配长度为4)   
                  b   =   "testa";   //这条语句实际是调用CString::operator=(CString&)函数。   
                                                b指向一新分配的引用内存块。(新分配的引用内存块的   
                                                引用计数为1,长度为5,分配长度为5)   
                                            //同时原引用内存块引用计数减1.   a、d与str仍指向原   
                                              引用内存块(引用内存块的引用计数为3,长度为4,分配长度为4)     
                                            
            }//由于d生命结束,调用析构函数,导至引用计数减1(引用内存   
                块的引用计数为2,长度为4,分配长度为4)   
            LPTSTR   temp   =   a.GetBuffer(10);//此语句也会导致重新分配新内存块。   
                                                                        temp指向新分配引用内存块的串首地址(新   
                                                                        分配的引用内存块的引用计数为1,长度   
                                                                        为0,分配长度为10)   
                                                                        //同时原引用内存块引用计数减1.   只有str仍   
                                                                            指向原引用内存块(引用内存块的引用计数为1,   
                                                                             长度为4,分配长度为4)                                               
            strcpy(temp,   "temp");     //a指向的引用内存块的引用计数为1,长度为0,分配长度为   
  10   
            a.ReleaseBuffer();//注意:a指向的引用内存块的引用计数为1,长度为4,分配长度为   
  10   
        }   
        //执行到此,所有的局部变量生命周期都已结束。对象str   a   b   各自调用自己的析构构   
        //函数,所指向的引用内存块也相应减1   
        //注意,str   a   b   所分别指向的引用内存块的计数均为0,这导致所分配的内存块释放   
          
          通过观察上面执行过程,我们会发现CString虽然可以多个对象指向同一引用内块存,   
  但是它们在进行各种拷贝、赋值及改变串内容时,它的处理是很智能并且非常安全的,完全   
  做到了互不干涉、互不影响。当然必须要求你的代码使用正确恰当,特别是实际使用中会有   
  更复杂的情况,如做函数参数、引用、及有时需保存到CStringList当中,如果哪怕有一小   
  块地方使用不当,其结果也会导致发生不可预知的错误   
    
  5     FreeExtra()的作用   
        看这段代码   
        (1)       CString   str("test");   
        (2)       LPTSTR   temp   =   str.GetBuffer(50);   
        (3)       strcpy(temp,   "there   are   22   character");   
        (4)       str.ReleaseBuffer();   
        (5)       str.FreeExtra();   
        上面代码执行到第(4)行时,大家都知道str指向的引用内存块计数为1,长度为22,分配长   
  度为50.   那么执行str.FreeExtra()时,它会释放所分配的多余的内存。(引用内存块计数为   
  1,长度为22,分配长度为22)   
    
  6     Format(...)     与   FormatV(...)   
        这条语句在使用中是最容易出错的。因为它最富有技巧性,也相当灵活。在这里,我没   
  打算对它细细分析,实际上sprintf(...)怎么用,它就怎么用。我只提醒使用时需注意一点   
  :就是它的参数的特殊性,由于编译器在编译时并不能去校验格式串参数与对应的变元的类   
  型及长度。所以你必须要注意,两者一定要对应上,   
        否则就会出错。如:   
        CString   str;   
        int   a   =   12;   
        str.Format("first:%l,   second:   %s",   a,   "error");//result?试试   

    
  7     LockBuffer()   与   UnlockBuffer()   
        顾名思议,这两个函数的作用就是对引用内存块进行加锁及解锁。   
        但使用它有什么作用及执行过它后对CString串有什么实质上的影响。其实挺简单,看下   
  面代码:   
        (1)       CString   str("test");   
        (2)       str.LockBuffer();   
        (3)       CString   temp   =   str;   
        (4)       str.UnlockBuffer();   
        (5)       str.LockBuffer();   
        (6)       str   =   "error";   
        (7)       str.ReleaseBuffer();   
        执行完(3)后,与通常情况下不同,temp与str并不指向同一引用内存块。你可以在watch   
  窗口用这个表达式(CStringData*)((CStringData*)(str.m_pchData)-1)看看。   
        其实在msdn中有说明:   
                  While   in   a   locked   state,   the   string   is   protected   in   two   ways:     
    
                        No   other   string   can   get   a   reference   to   the   data   in   the   locked     
  string,   even   if   that   string   is   assigned   to   the   locked   string.   
                        The   locked   string   will   never   reference   another   string,   even   if   that     
  other   string   is   copied   to   the   locked   string.     
    
  8     CString   只是处理串吗?   
        不对,CString不只是能操作串,而且还能处理内存块数据。功能完善吧!看这段代码   
          char     p[20];   
          for(int   loop=0;   loop<sizeof(p);   loop++)   
          {   
                  p[loop]   =   10-loop;   
          }   
          CString   str((LPCTSTR)p,   20);   
          char   temp[20];   
          memcpy(temp,   str,   str.GetLength());   
          str完全能够转载内存块p到内存块temp中。所以能用CString来处理二进制数据   
    
  8     AllocSysString()与SetSysString(BSTR*)     
        这两个函数提供了串与BSTR的转换。使用时须注意一点:当调用AllocSysString()后,   
  须调用它SysFreeString(...)     
    
  9     参数的安全检验   
        在MFC中提供了多个宏来进行参数的安全检查,如:ASSERT.     其中在CString中也不例外   
  ,有许多这样的参数检验,其实这也说明了代码的安全性高,可有时我们会发现这很烦,也   
  导致Debug与Release版本不一样,如有时程序Debug通正常,而Release则程序崩溃;而有时   
  恰相反,Debug不行,Release行。其实我个人认为,我们对CString的使用过程中,应力求   
  代码质量高,不能在Debug版本中出现任何断言框,哪怕release运行似乎   
        看起来一切正常。但很不安全。如下代码:   
        (1)       CString   str("test");   
        (2)       str.LockBuffer();   
        (3)       LPTSTR   temp   =   str.GetBuffer(10);   
        (4)       strcpy(temp,   "error");   
        (5)       str.ReleaseBuffer();   
        (6)       str.ReleaseBuffer();//执行到此时,Debug版本会弹出错框   
    
  

Top
6楼  code8238   (二进制动物)   回复于 2004-03-31 08:03:31  得分 0 
10   CString的异常处理   
        我只想强调一点:只有分配内存时,才有可能导致抛出CMemoryException.   
        同样,在msdn中的函数声明中,注有throw(   CMemoryException)的函数都有重新分配或   
  调整内存的可能。   
    
  11   跨模块时的CString.即一个DLL的接口函数中的参数为CString&时,它会发生怎样的现   
  象。解答我遇到的   
    
      构造一个这样CString对象时,如CString   str,你可知道此时的str所指向的引用内存块   
  吗?也许你会认为它指向NULL。其实不对,如果这样的话,CString所采用的引用机制管理   
  内存块就会有麻烦了,所以CString在构造一个空串的对象时,它会指向一个固定的初始化   
  地址,这块数据的声明如下:   
        AFX_STATIC_DATA   int   _afxInitData[]   =   {-1,0,0,0};   
      简要描述概括一下:当某个CString对象串置空的话,如Empty(),CString   a等,它的成员   
  变量m_pchData就会指向_afxInitData这个变量的地址。当这个CString对象生命周期结束时   
  ,正常情况下它会去对所指向的引用内存块计数减1,如果引用计数为0(即没有任何CString   
  引用时),则释放这块引用内存。而现在的情况是如果CString所指向的引用内存块是初始化   
  内存块时,则不会释放任何内存。   
    
      说了这么多,这与我遇到的问题有什么关系呢?其实关系大着呢?其真正原因就是如果   
  exe模块与dll模块有一   
      个是static编译连接的话。那么这个CString初始化数据在exe模块与dll模块中有不同的   
  地址,因为static连接则会在本模块中有一份源代码的拷贝。另外一种情况,如果两个模块   
  都是share连接的,CString的实现代码则在另一个单独的dll实现,而AFX_STATIC_DATA指定   
  变量只装一次,所以两个模块中_afxInitData有相同的地址。   
      现在问题完全明白了吧!你可以自己去演示一下。   
      __declspec   (dllexport)   void   test(CString&   str)   
      {   
          str   =   "abdefakdfj";//如果是static连接,并且传入的str为空串的话,这里出错。   
      }   
    
  最后一点想法:写得这里,其实CString中还有许多技巧性的好东东,我并没去解释。如很   
  多重载的操作符、查找等。我认为还是详细看看msdn,这样会比我讲好多了。我只侧重那些   
  情况下会可能出错。当然,我叙述如有错误,敬请高手指点,不胜感谢!   
    
    
  sorry,改正一下   
    
        看起来一切正常。但很不安全。如下代码:   
        (1)       CString   str("test");   
        (2)       str.LockBuffer();   
        (3)       LPTSTR   temp   =   str.GetBuffer(10);   
        (4)       strcpy(temp,   "error");   
        (5)       str.ReleaseBuffer();   
        (6)       str.UnlockBuffer();//执行到此时,Debug版本会弹出错框

 

  • 2
    点赞
  • 3
    收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页
评论

打赏作者

此间的年少

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值