1. 程式人生 > >VC++中字串轉換CString, char*, BSTR, 多位元組,unicode字符集轉換的問題

VC++中字串轉換CString, char*, BSTR, 多位元組,unicode字符集轉換的問題

_T的意思是通知編譯器,自行進行字串的多位元組/Unicode轉換。
而L表示,該字串為Unicode版本。
http://www.blogjava.net/neumqp/archive/2006/03/09/34504.html

先區別一下字元陣列和字元指標變數

(1)字元陣列是由若干個元素組成的,每個元素中放了一個字元,而字元指標變數中存放的是地址(字串第一個字元的地址),絕不是將字串存放到字元指標變數中

(2)賦值方式。對字元陣列只能對各個元素賦值,不能用以下辦法對字元陣列賦值:

char str[14];

str="I love you";

而對字元指標變數,可以採用下面方法賦值:

char* a;

a="I love you";

但是,注意賦給a的不是字元,而是字串第一個元素的地址。

(3)對字元指標變數賦初值

char * a="I love you";

等價於

char* a;

a="I love you";

而對陣列的初始化:

char str[14]={"I love you"};

不能等價於

char str[14];

str[]="I love you";

即陣列可以在定義時整體賦初值,但不能在賦值語句中整體賦值。

(4)如果定義了一個字元陣列,在編譯時已經為它分配了記憶體單元,它有確定的地址。而定義一個字元指標變數時,在沒有給其賦值的前提下,它並沒有一個確定的地址;只有賦值字串後,才確定了地址,才可以指向一個字串。可以如下方式

char *a, str[10];

a=str;

然後,就可以用字元指標變數的下標形式引用字元了。

還有一點,特別注意,字元陣列名雖然代表地址,它他是常量,它的值值不能改變的。下面是錯誤的

char str[]={"I love you"};

str=str+7;

printf("%s",str);

而指標變數的值是可以改變的,指向的是地址。下面是正確的:

char* a="I love you";

a=a+7;

printf("%s",a);//結果為 you 

========================================================================

char*,const char*和string的相互轉換

1. string轉const char*

   string s = "abc";

   const char* c_s =s.c_str();

2. const char*轉string

   直接賦值即可

   const char* c_s ="abc";

   string s(c_s);

3. string轉char*

   string s = "abc";

   char* c;

   const int len =s.length();

   c = new char[len+1];

   strcpy(c,s.c_str());  //s.data()也可以。主要,現將string轉const char*,然後再通過strcpy轉

4. char*轉string

   char* c = "abc";

   string s(c);//建構函式的方式

5. const char*轉char*

   const char* cpc ="abc";

   char* pc = newchar[100];//足夠長

   strcpy(pc,cpc);

6. char*轉const char*

   直接賦值即可

   char* pc = "abc";

   const char* cpc = pc;

extern "C" char* hello(char* name)
{
	CString names="";
	names.Format("%s",name);
	CString cs="Hello JNA world, ";
	cs+=names;

	//錯誤,
	//char* re=cs.GetBuffer(cs.GetLength());

	//正確,需要複製
	int len = cs.GetLength();
	char* c=new char[len+1];
	strcpy(c,cs.GetBuffer(len));
	return c;
	//AfxMessageBox(cs);
}
//char 陣列相連
    char*b="bc";
    char*c="ef";

    char* p=new char(27);
    memset(p,0,27);//設定初值
    strcpy(p,b);
    strcat(p,c);

    CString cs;
    cs.Format("%s",p);
    CString len;
    len.Format("%d",cs.GetLength()); //注意此時的長度,並不是先前定義的27,與memset設定初值有關。請測試。

    MessageBox(cs+"長度為"+len);

     //另外,將char型連線到char*的後面
    char*b="bc";
    char*c="ef";

    char* p=new char(27);
    memset(p,0,27);//先賦初值後,在通過下標引用。否則p中的內容會出現亂碼形式。
    strcpy(p,b);
    strcat(p,c);
    char a='a'; 
    p[strlen(p)]=a;//重點。
main()
{
char str1[10]="world!";
char str2[20]="hello ";
strcpy(str2+strlen(str2),str1);
printf("%s",str2);
}
    //==================沒有上個簡單
    char gray[] = "Gray";
    char cat[] = "Cat";
    char * graycat =(char*) malloc(strlen(gray) + strlen(cat) + 1);
    strcpy(graycat, gray);
    strcat(graycat, cat);
    //================== 
CString 和string
CString->std::string 例子:
CString strMfc=“test“;
std::string strStl;
strStl=strMfc.GetBuffer(0);
strMfc.ReleaseBuffer();//要釋放

std::string->CString  例子:
CString strMfc;
std::string strStl=“test“;
strMfc=strStl.c_str();

CString和char*在第四部分

=======================================================================================

BSTR, _bstr_t, CComBSTR, CString

這裡總結了BSTR, _bstr_t, CComBSTR, CString四種字串型別之間的轉換。其中BSTR為基本資料型別,另三個為字串類。

首先宣告四個型別的變數:

BSTR           strBigBSTR          = ::SysAllocString( _T( "BSTR" ));

_bstr_t         strSmallBSTR( _T( “_bstr_t” ))  ;

CComBSTR strCComBSTR( _T( “CComBSTR” ))

CString          strCString( _T( “CString” ));

       CComBSTR strTempCComBSTR( _T( “TempCComBSTR” ));

1.    BSTR to Other Type

BSTR轉換為其他型別非常方便,直接使用類的建構函式即可

// BSTR to _bstr_t

strSmallBSTR = _bstr_t( strBigBSTR );

// BSTR to CComBSTR

strCComBSTR = CComBSTR( strBigBSTR );

// BSTR to CString

strCString = CString( strBigBSTR );

2.    _bstr_t to Other Type

基本思想是先把_bstr_t轉化為TCHAR*, 再轉化為其他型別。

// _bstr_t to BSTR

strTempCComBSTR = CComBSTR( static_cast<TCHAR*>( strSmallBSTR ));

strBigBSTR = strTempCComBSTR.m_str;

// _bstr_t to CComBSTR

strCComBSTR = CComBSTR( static_cast<TCHAR*>( strSmallBSTR ));

// _bstr_t to CString

strCString = CString( static_cast<TCHAR*>( strSmallBSTR ));

_bstr_t類過載了操作符char*和wchar_t*(TCHAR*的兩種形式),所以這裡並不是使用強制轉換,而是呼叫了_bstr_t的函式。

3.    CComBSTR to Other Type

基本思想是使用CComBSTR的公有成員變數m_str進行轉換。

// CComBSTR to BSTR

strBigBSTR = strCComBSTR.m_str;

// CComBSTR to _bstr_t

strSmallBSTR = _bstr_t( strCComBSTR.m_str );

// CComBSTR to CString

strCString = CString( strCComBSTR.m_str );

4.    CString to Other Type

基本思想是先把CString轉化為LPCTSTR, 再轉化為其他型別。

// CString to BSTR

strTempCComBSTR = CComBSTR( static_cast<LPCTSTR>( strCString ));

strBigBSTR = strTempCComBSTR.m_str;

// CString to _bstr_t

strSmallBSTR = _bstr_t( static_cast<LPCTSTR>( strCString ));

// CString to CComBSTR

strCComBSTR = CComBSTR( static_cast<LPCTSTR>( strCString ));

CString類過載了操作符LPCTSTR,所以這裡並不是使用強制轉換,而是呼叫了CString的函式。

5.    注意事項:

其他型別轉化為BSTR型別時都使用的CComBSTR作為中轉,因為這樣不需要自己釋放記憶體。但是要注意的是,轉換後BSTR指向的是CComBSTR的記憶體,所以一旦CComBSTR被銷燬了,BSTR也就失效了,這樣會導致不可預知的錯誤。所以一定要保證CComBSTR大於或等於BSTR的週期。

下面用法是錯誤的:

strBigBSTR = CComBSTR(( LPCTSTR )strCString ).m_str;

因為CComBSTR在此條語句結束後就被析構了。

===============================================

VC裡一般都提供CString的介面 

 
 否則也有LPCTSTR的。  
 如果是LPCTSTR可以直接用CString轉換  
  CString  str;  
 (LPCTSTR)str就是LPCTSTR的了。  
  char  *  也可以這麼轉換成LPCTSTR。  
   
char 不能直接轉換成CString,CString 也不能直接轉換成char 但是有了LPCTSTR就可以了。哈哈 
  char  *  p  
  CString  str;  
  p  =  (char*)(LPCTSTR)str;  
  str  =  (CString)(LPCTSTR)p;  
   
所以,對我來說,LPCTSTR是用來轉換的過度工具,它能幹什麼?我不管。反正我這麼用就足夠了。

在程式碼中未定義 UNICODE的情況下
LPTSTR    等價於 char *
LPCSTR    等價於 const char *

所以直接使用就是了。 char temp[6] = "abcd";
LPTSTR lptstr = (LPTSTR)temp;
LPCTSTR lpctstr = (LPCTSTR)temp;

string wstring _bstr_t的互相轉換

 string       ansi字串
  wstring    unicode字串
  _bstr_t     com字串
  之間的轉換關係,示例如下:
  // ex_02_wstring_cv_string.cpp : 定義控制檯應用程式的入口點。
  //
  #include "stdafx.h"
  #include "string"
  #include "icrsint.h"
  #include "comutil.h"
  using namespace std;
  #import "C:\\Program Files\\Common Files\\System\\ADO\\msado15.dll" no_namespace rename("EOF", "EndOfFile")
  int _tmain(int argc, _TCHAR* argv[])
  {
  CoInitialize(NULL);
  wstring ws1,ws2;
  ws2 = L"春如舊,人空瘦,淚痕紅浥鮫綃透。桃花落,閒池閣,山盟雖在,錦書難託。莫、莫、莫。";
  // 從 unicode 字串轉化為 ansi字串
  string s = (char *) _bstr_t ( ws2.c_str() );
  // 從 ansi字串轉化為 unicode 字串
  ws1 = ( wchar_t *) ( _bstr_t ( s.c_str( ) ));
  setlocale(LC_ALL, "chs");
  wprintf( L"原wstring串=%s\n",ws2.c_str());
  printf( "轉換為string串=%s\n", s.c_str());
  wprintf( L"轉換為wstring串=%s\n",ws1.c_str());
  ::CoUninitialize();
  getchar();
  return 0;
  }
  --- 結果 ---
  原wstring串=春如舊,人空瘦,淚痕紅浥鮫綃透。桃花落,閒池閣,山盟雖在,錦書難託。莫、莫、莫。
  轉換為string串=春如舊,人空瘦,淚痕紅浥鮫綃透。桃花落,閒池閣,山盟雖在,錦書難託。莫、莫、莫。
  轉換為wstring串=春如舊,人空瘦,淚痕紅浥鮫綃透。桃花落,閒池閣,山盟雖在,錦書難託。莫、莫、莫。


=======================================================================================

一、CString與LPCWSTR 

    兩者的不同:LPCWSTR 是Unicode字串指標,初始化時串有多大,申請空間就有多大,以後存貯若超過則出現無法預料的結果,這是它與CString的不同之處。而CString是一個串類,記憶體空間類會自動管理。

  1、  CString轉換成LPCWSTR

    方法一:CString strFileName;

                     LPCWSTR lpcwStr = strFileName.AllocSysString();

    方法二:CString str=_T("TestStr"); 
                    USES_CONVERSION; 
                    LPCWSTR lpcwStr = A2CW((LPCSTR)str);

        MFC中CString和LPSTR是可以通用(在Unicode字符集中不成立),其中A2CW表示(LPCSTR)  -> (LPCWSTR),USER_CONVERSION表示用來定義一些中間變數,在使用ATL的轉換巨集之前必須定義該語句。

    2、LPCWSTR轉換成CString

    LPCWSTR lpcwStr = L"TestWStr"; 
    CString str(lpcwStr);  //CString的其中一個建構函式

   二、CString與LPWSTR         

                  1、CString轉LPWSTR

                  CString str;

                   LPWSTR  lpstr = (LPWSTR)(LPCWSTR)str;

                  2、LPWSTR轉CString (一般沒有用)

                     LPWSTR lpwStr = L"TestWStr"; 
                     CString str(lpwStr);  //CString的其中一個建構函式

三、CString與LPSTR轉換

     1、CString轉換成LPSTR:

    方法一:CString strFileName;

                    LPSTR lpStr = strFileName.GetBuffer();

                    strFileName.ReleaseBuffer();

     方法二:(比較下CString轉LPWSTR,都是先強制轉成const字元常量,然後再強制轉成字元變數)

                     CString strFileName;

                     LPSTR lpStr = (LPSTR)(LPCSTR)strFimeName;

   2、   LPSTR轉換成CString(利用CString的建構函式):

                      LPSTR lpStr = L"TestStr"; 
                      CString str(lpStr);

                 注意:CString和LPCSTR可直接轉換,如下:

                     CString str;

                     LPCSTR lpcStr = (LPCSTR)str;

四、CString和char*轉換
    CString 是一種很特殊的 C++物件,它裡面包含了三個值:一個指向某個資料緩衝區的指標、一個是該緩衝中有效的字元記數(它是不可存取的,是位於 CString 地址之下的一個隱藏區域)以及一個緩衝區長度。有效字元數的大小可以是從0到該緩衝最大長度值減1之間的任何數(因為字串結尾有一個NULL字元)。字元記數和緩衝區長度被巧妙隱藏。

(1) char*轉換成CString

  若將char*轉換成CString,除了直接賦值外,還可使用CString::Format進行。例如:

 char chArray[] = "Char test";

TCHAR * p = _T("Char test");

( 或LPTSTR p = _T("Char test");)

CString theString = chArray;
theString.Format(_T("%s"), chArray); theString = p;


(2) CString轉換成char*(非unicode字符集)

  若將CString類轉換成char*(LPSTR)型別,常常使用下列三種方法:

  方法一,使用強制轉換。例如:

CString theString( (_T("Char test "));

LPTSTR lpsz=(LPTSTR)(LPCTSTR)theString;

  方法二,使用strcpy。例如:

這種方法在有些地方特別有效,特別在強制轉換不成功時

CString theString( (_T("Char test "));

LPTSTR lpsz = new TCHAR[theString.GetLength()+1];

_tcscpy(lpsz, theString);

  需要說明的是,strcpy(或可移值的_tcscpy)的第二個引數是 const wchar_t* (Unicode)或const char* (ANSI),系統編譯器將會自動對其進行轉換。

  方法三,使用CString::GetBuffer。

如果你需要修改 CString 中的內容(因為CString是字串常量,和LPCSTR等價),它有一個特殊的方法可以使用,那就是GetBuffer,它的作用是返回一個可寫的緩衝指標。
如果你只是打算修改字元或者截短字串,例如:

CString s(_T("Char test"));

LPTSTR p = s.GetBuffer();

LPTSTR dot = strchr(p, ''.'');


// 在這裡新增使用p的程式碼

if(p != NULL)

*p = _T('');

s.ReleaseBuffer(); //

使用完後及時釋放,以便能使用其它的CString成員函式

char *p;
CString str="hello";
p=str.GetBuffer(str.GetLength());
str.ReleaseBuffer();將CString轉換成char * 時

----
CString str("aaaaaaa");
strcpy(str.GetBuffer(10),"aa");

str.ReleaseBuffer();

在 GetBuffer 和 ReleaseBuffer之間這個範圍,一定不能使用你要操作的這個緩衝的 CString物件的任何方法。因為 ReleaseBuffer 被呼叫之前,該 CString物件的完整性得不到保障。
五、CString和int、float的轉換

  可以使用atoi,atof,atol等函式來完成。     

CString strFloat;
float flt;

//method1:
flt = (float)atof((char *)(LPTSTR)(LPCTSTR)mstrFloat);//強制轉換,不推薦

//method2:
flt = (float)atof((char *)m_eps.GetBuffer(strFloat.GetLength()));
strFloat.ReleaseBuffer();

六、LPSTR(char*)和LPWSTR的轉換

        可以使用下面的ATL巨集來進行,最好是將變數定義成TCHAR、LPTSTR等T型別,可以避免轉換。

ATL巨集介紹:

     A2BSTR   OLE2A             T2A            W2A 
     A2COLE   OLE2BSTR    T2BSTR    W2BSTR 
     A2CT         OLE2CA         T2CA          W2CA 
     A2CW        OLE2CT         T2COLE    W2COLE 
     A2OLE       OLE2CW       T2CW         W2CT 
     A2T            OLE2T            T2OLE        W2OLE 
     A2W           OLE2W          T2W             W2T

    A :ANSI 字串,也就是 MBCS。 
    W、OLE 寬字串,也就是 UNICODE。 
    T 中間型別T。如果定義了 _UNICODE,則T表示W;如果定義了 _MBCS,則T表示A 
    C const 的縮寫

利用這些巨集,可以快速的進行各種字元間的轉換。使用前必須包含標頭檔案,並且申明USER_CONVERSION;使用 ATL 轉換巨集,由於不用釋放臨時空間,所以使用起來非常方便。但是考慮到棧空間的尺寸(VC 預設2M),使用時要注意幾點:

    1、只適合於進行短字串的轉換; 
    2、不要試圖在一個次數比較多的迴圈體內進行轉換; 
    3、不要試圖對字元型檔案內容進行轉換,因為檔案尺寸一般情況下是比較大的; 
    4、對情況 2 和 3,要使用 MultiByteToWideChar() 和 WideCharToMultiByte();

void Func1(LPSTR lpStr);

void Func2(LPWSTR lpwStr);

TCHAR   name[256];

TCHAR*   pName = new  TCHAR[256];

Func1(name); // Func1(pName);

Func2(name); // Func2(pName);

(說明)注意在VS2005中上面用紅色標記的程式碼已經不成立。VS2005中CString已經改為寬字元型,一些轉換如下:

char name[10];
 TCHAR sex[5] ;
 char *p = name;
 TCHAR *pw = sex;

 LPSTR lpstr = name;
 LPCSTR lpcstr = name;


 lpcstr = lpstr;//可直接賦值,字元變數給字元常量賦值
 lpstr = p; //本來相等

----------------------------------------------------------------------------
 p = (char*)sex;
 pw = (WCHAR*)name;


 LPWSTR lpwstr = (LPWSTR)lpstr;
 LPCWSTR lpcwstr = (LPCWSTR)lpstr;

 lpwstr = (LPWSTR)lpcstr;
 lpcwstr = (LPCWSTR)name;

--------------------------------------------------------------------------

//採用CString的建構函式

 CString str(lpstr);
 CString str1(lpcstr);
 CString str2(lpwstr);
 CString str3(lpcwstr);
 CString str4(name);
 CString str5(sex);

//特別注意,此處的轉換方式,CString與LPSTR, LPCSTR, 都是先轉成寬字元,然後再轉成對應的型別(見上面紅色說明)

 lpwstr = (LPWSTR)(LPCWSTR)str;
 lpstr = (LPSTR)(LPCWSTR)str;//在Unicode編碼下不成立,不能強制轉換

 lpcstr = (LPCSTR)(LPCWSTR)str;

 p = (char*)str.GetBuffer();//錯誤,不能強制轉換
 pw = str.GetBuffer();

可以看出轉換更加簡單了,基本上可以直接轉換,A2W等巨集基本上不需要啦

測試如下程式碼會出現亂碼,需注意(在VS2008的ATL工程下,unicode字符集),強制轉換會出錯

	LPCSTR p3="中華人民共和國";
	LPCWSTR lpcwStr3 = (LPCWSTR)p3;
	MessageBox(lpcwStr3);
如下程式碼正確(在ATL中添加了MFC支援),採用CString中間轉換可以
	LPCSTR p="中華人民共和國";
	CString strFileName(p);
	LPCWSTR lpcwStr = strFileName.AllocSysString();
	MessageBox(lpcwStr);
或者下面也正確
	LPCSTR p3="中華人民共和國3";
	CString strFileName3(p3);
	LPCWSTR lpcwStr3 = (LPCWSTR)strFileName3;
	MessageBox(lpcwStr3);
CString轉wchar_t*
		CString theString=_T("你好!");
		wchar_t* lpsz = new wchar_t[theString.GetLength()+1];
		_tcscpy(lpsz, theString);
		MessageBox(lpsz);
或者
		CString theString=_T("你好!");
		wchar_t* wcs=theString.GetBuffer();
		MessageBox(wcs);
		wcs=NULL;
		theString.ReleaseBuffer();//此處要釋放
或者
		CString theString=_T("你好!");
		LPCWSTR lpcwStr = theString.AllocSysString();
		MessageBox(lpcwStr);

在沒有MFC支援的情況下,參考下面的內容
===========================================================

多位元組字串與寬字串的轉換可使用C API者Win32 API.C API: mbstowcs,wcstombsWin32 API: MultiByteToWideChar, WideCharToMultiByte下面著重介紹Win32 API的用法,C API的用法較為簡單可參照Win32 API。首先是WideCharToMultiByte通常你需要配置4個引數(其他引數如是使用即可),依次是源寬字串,需要轉換的長度(-1,則為轉換整個字串),目標多位元組字串,目標緩衝區長度。返回值表示轉換為目標多位元組字串實際需要的長度(包括結束符)。所以通常需要呼叫WideCharToMultiByte兩次:第一次產生目標緩衝區長度,第二次產生目標字串,像下面這樣

	wchar_t* wcs = L"中國,你好!I Love You!";
	int lengthOfMbs = WideCharToMultiByte( CP_ACP, 0, wcs, -1, NULL, 0, NULL, NULL);
	char* mbs = new char[ lengthOfMbs ];
	WideCharToMultiByte( CP_ACP, 0, wcs, -1, mbs, lengthOfMbs, NULL, NULL);
	delete mbs;
	mbs = NULL;

	//=============
	char* mbs = "中國,你好!I Love You!";
	int lengthOfWcs = MultiByteToWideChar( CP_ACP, 0, mbs, -1, NULL, 0 );
	wchar_t* wcs = new wchar_t[ lengthOfWcs ];
	MultiByteToWideChar( CP_ACP, 0, mbs, -1, wcs, lengthOfWcs );
	delete wcs;
	wcs = NULL;

測試如下,正確、無亂碼
	//=============
	char* mbs2 = "中國,你好!I Love You!";
	int lengthOfWcs = MultiByteToWideChar( CP_ACP, 0, mbs2, -1, NULL, 0 );
	wchar_t* wcs2 = new wchar_t[ lengthOfWcs ];
	MultiByteToWideChar( CP_ACP, 0, mbs2, -1, wcs2, lengthOfWcs );
	LPCWSTR lpcwStr2 = (LPCWSTR)wcs2;
	MessageBox(lpcwStr2);
	delete wcs2;
	wcs2 = NULL;

將CString轉為char*  LPSTR
		CString mstr=_T("您好!");
		char* mc= (LPSTR)(LPCWSTR)mstr;//此處錯誤

		//先轉成寬字串,然後再利用WideCharToMultiByte方法
		wchar_t* wcs=mstr.GetBuffer();
		int lengthOfMbs = WideCharToMultiByte( CP_ACP, 0, wcs, -1, NULL, 0, NULL, NULL);  
		char* mbs = new char[ lengthOfMbs ];  
		WideCharToMultiByte( CP_ACP, 0, wcs, -1, mbs, lengthOfMbs, NULL, NULL);

		CString cs(mbs);
		MessageBox(cs);
轉載
//將單位元組char*轉化為寬位元組wchar_t*  
wchar_t* AnsiToUnicode( const char* szStr )  
{  
    int nLen = MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, szStr, -1, NULL, 0 );  
    if (nLen == 0)  
    {  
        return NULL;  
    }  
    wchar_t* pResult = new wchar_t[nLen];  
    MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, szStr, -1, pResult, nLen );  
    return pResult;  
}  
  
//將寬位元組wchar_t*轉化為單位元組char*  
inline char* UnicodeToAnsi( const wchar_t* szStr )  
{  
    int nLen = WideCharToMultiByte( CP_ACP, 0, szStr, -1, NULL, 0, NULL, NULL );  
    if (nLen == 0)  
    {  
        return NULL;  
    }  
    char* pResult = new char[nLen];  
    WideCharToMultiByte( CP_ACP, 0, szStr, -1, pResult, nLen, NULL, NULL );  
    return pResult;  
}  

===========================================================================================

也談C++中char*與wchar_t*之間的轉換  

關於C++中的char*wchar_t*這兩種型別的相互轉換,網上說的大多很繁瑣,可行性也不高。下面這個方法是在MSDN裡面找到的,個人認為還比較不錯:

char*轉換為wchar_t*

stdlib.h中的mbstowcs_s函式,可以通過下面的例子瞭解其用法:

char *CStr ="string to convert";

size_t len = strlen(CStr) + 1;

size_t converted = 0;

wchar_t *WStr;

WStr=(wchar_t*)malloc(len*sizeof(wchar_t));

mbstowcs_s(&converted, WStr, len, CStr, _TRUNCATE);

其結果是WStr中儲存了CStrwchar_t版本。

wchar_t*轉換為char*

和上面的方法類似,用stdlib.h中的wcstombs_s函式,例子:

wchar_t *WStr = L"string to convert";

size_t len = wcslen(WStr) + 1;

size_t converted = 0;

char *CStr;

CStr=(char*)malloc(len*sizeof(char));

wcstombs_s(&converted, CStr, len, WStr, _TRUNCATE);

這時WStr中的內容將被轉化為char版本儲存在CStr中。

另外還可以通過流的方法來char*型別轉換為wchar_t*型別,但這樣的轉換得到的結果將是const型別,而類似的方法不能將wchar_t*型別轉換為char*型別。

把(constchar*轉換為const wchar_t*

需要用到 sstream 標頭檔案:

char *cstr="string to convert";

wstringstream wss;

wss<<cstr;

再呼叫wss.str().c_str();即可得到 const wchar_t*型別的返回值。

雖然stringstream流不能將wchar_t*轉換成char*,但可以用來進行數值型別和字串之間的轉換,例如:

double d=2734792.934f;

stringstream ss;

ss<<d;

呼叫ss.str()可得到string型別字串 ”273479e+006”,又如:

string str("299792458");

stringstream ss;

long i=0;

ss<<str;

ss>>i;

此時i=299792458

===========================================================

 首先在編譯程式時經常會遇到這種問題:

錯誤 1 error C2664: “CWnd::MessageBoxW”: 不能將引數 1 從“const char [3]”轉換為“LPCTSTR”

1、覺得很煩,一般的做法就是不管三七二十一,在字串前面加一個‘L’

如呼叫函式FUN(LPCTSTR str)時,不能  FUN("HELLO");     而是FUN(L"HELLO");通常這樣做都比較能解決問題。

2、或者還可以用_T(), 即 FUN(_T("HELLO"));   _T() 的別名還有 _TEXT(), TEXT()。

稍微研究了下,BSTR,LPSTR,LPWSTR,LPCTSTR,LPTSTR等這些讓人頭暈的東東。(還是C#裡簡單啊,直接tostring)

BSTR:是一個OLECHAR*型別的Unicode字串,是一個COM字串,帶長度字首,與VB有關,沒怎麼用到過。

LPSTR:即 char *,指向以'/0'結尾的8位(單位元組)ANSI字元陣列指標

LPWSTR:即wchar_t *,指向'/0'結尾的16位(雙位元組)Unicode字元陣列指標

LPCSTR:即const char *

LPCWSTR:即const wchar_t *

 注意下面兩個型別

LPTSTR:LPSTR、LPWSTR兩者二選一,取決於是否巨集定義了UNICODE或ANSI

LPCTSTR: LPCSTR、LPCWSTR兩者二選一,取決於是否巨集定義了UNICODE或ANSI,如下是從MFC庫中拷來的:

#ifdef UNICODE

    typedef LPWSTR LPTSTR;

    typedef LPCWSTR LPCTSTR;

#else

    typedef LPSTR LPTSTR;

    typedef LPCSTR LPCTSTR;

#endif

3、相互轉換方法

LPWSTR->LPTSTR:   W2T();
LPTSTR->LPWSTR:   T2W();
LPCWSTR->LPCSTR: W2CT();
LPCSTR->LPCWSTR: T2CW();

ANSI->UNICODE:     A2W();

UNICODE->ANSI:     W2A();

另外,CString轉為CStringW方法(通過一個wchar_t陣列來轉)

 CString str;

 CStringW strw;
 wchar_t *text = new wchar_t[sizeof(wchar_t) * str.GetLength()];
 MultiByteToWideChar(CP_ACP,0,str,-1,text,str.GetLength());
 strw = text;

4、另外,還可以強行轉換,不過不一定能成功

5、還有_bstr_t ( 對BTSTR的封裝,需要#include<comdef.h> ),也可將單位元組字元陣列指標轉為雙位元組字元陣列指標,還沒怎麼沒用到過。

==========================================================

L表示long指標

這是為了相容Windows 3.1等16位作業系統遺留下來的,在win32中以及其他的32為作業系統中, long指標和near指標及far修飾符都是為了相容的作用。沒有實際意義。
P表示這是一個指標
C表示是一個常量

T表示在Win32環境中, 有一個_T巨集,這個巨集用來表示你的字元是否使用UNICODE, 如果你的程式定義了UNICODE或者其他相關的巨集,那麼這個字元或者字串將被作為UNICODE字串,否則就是標準的ANSI字串。
STR表示這個變數是一個字串

所以LPCTSTR就表示一個指向常固定地址的可以根據一些巨集定義改變語義的字串。或者為LPCSTR ,或者為LPCWSTR
同樣, LPCSTR就只能是一個ANSI字串,在程式中我們大部分時間要使用帶T的型別定義。

LPCTSTR == const TCHAR *

CString 和 LPCTSTR 可以說通用。 原因在於CString定義的自動型別轉換,沒什麼奇特的,最簡單的C++操作符過載而已。

常量字串ansi和unicode的區分是由巨集_T來決定的。但是用_T("abcd")時,字串"abcd"就會根據編譯時的是否定一_UNICODE來決定是char* 還是 w_char*。 同樣,TCHAR 也是相同目的字元巨集。看看定義就明白了。簡單起見,下面只介紹 ansi 的情況,unicode 可以類推。

ansi情況下,LPCTSTR 就是 const char*, 是常量字串(不能修改的)。
而LPTSTR 就是 char*, 即普通字串(非常量,可修改的)。

這兩種都是基本型別, 而CString 是 C++類, 相容這兩種基本型別是最起碼的任務了。

由於const char* 最簡單(常量,不涉及記憶體變更,操作迅速), CString 直接定義了一個型別轉換函式
operator LPCTSTR() {......}, 直接返回他所維護的字串。

當你需要一個const char* 而傳入了CString時, C++編譯器自動呼叫 CString過載的操作符 LPCTSTR()來進行隱式的型別轉換。
當需要CString , 而傳入了 const char* 時(其實 char* 也可以),C++編譯器則自動呼叫CString的建構函式來構造臨時的 CString物件。

因此CString 和 LPCTSTR 基本可以通用。
CString 轉LPCTSTR:
CString cStr;
const char *lpctStr=(LPCTSTR)cStr;

LPCTSTR轉CString:
LPCTSTR lpctStr;
CString cStr=lpctStr;

但是 LPTSTR又不同了,他是 char*, 意味著你隨時可能修改裡面的資料,這就需要記憶體管理了(如字串變長,原來的存貯空間就不夠了,則需要重新調整分配記憶體)。
所以 不能隨便的將 const char* 強制轉換成 char* 使用。
樓主舉的例子
LPSTR lpstr = (LPSTR)(LPCTSTR)string;
就是這種不安全的使用方法。

這個地方使用的是強制型別轉換,你都強制轉換了,C++編譯器當然不會拒絕你,但同時他也認為你確實知道自己要做的是什麼。因此是不會給出警告的。
強制的任意型別轉換是C(++)的一項強大之處,但也是一大弊端。這一問題在 vc6 以後的版本(僅針對vc而言)中得到逐步的改進(你需要更明確的型別轉換宣告)。

其實在很多地方都可以看到類似
LPSTR lpstr = (LPSTR)(LPCTSTR)string;
地用法,這種情況一般是函式的約束定義不夠完善的原因
,比如一個函式接受一個字串引數的輸入,裡面對該字串又沒有任何的修改,那麼該引數就應該定義成 const char*,但是很多初學者弄不清const地用法,或者是懶, 總之就是隨意寫成了 char* 。 這樣子傳入CString時就需要強制的轉換一下。

這種做法是不安全的,也是不被建議的用法,你必須完全明白、確認該字串沒有被修改

CString 轉換到 LPTSTR (char*), 預定的做法是呼叫CString的GetBuffer函式,使用完畢之後一般都要再呼叫ReleaseBuffer函式來確認修改 (某些情況下也有不呼叫ReleaseBuffer的,同樣你需要非常明確為什麼這麼做時才能這樣子處理,一般應用環境可以不考慮這種情況)。

同時需要注意的是, 在GetBuffer 和 ReleaseBuffer之間,CString分配了記憶體交由你來處理,因此不能再呼叫其他的CString函式。

=============================================================

1.區別wchar_t,char,WCHAR

   ANSI:即 char,可用字串處理函式:strcat( ),strcpy( ), strlen( )等以str打頭的函式。
   UNICODE:wchar_t是Unicode字元的資料型別,它實際定義在裡:
   typedef unsigned short wchar_t;
   另外,在標頭檔案中有這樣的定義:typedef wchar_t WCHAR; 所以WCHAR實際就是wchar_t
   wchar_t 可用字串處理函式:wcscat(),wcscpy(),wcslen()等以wcs打頭的函式。為了讓編譯器識別Unicode字串,必須以在前面加一個“L”,例如: wchar_t *szTest=L"This is a Unicode string.";

2.TCHAR

在C語言裡面提供了 _UNICODE巨集(有下劃線),在Windows裡面提供了UNICODE巨集(無下劃線),只要定了_UNICODE巨集和UNICODE巨集,系統就會自 動切換到UNICODE版本,否則,系統按照ANSI的方式進行編譯和執行。只定義了巨集並不能實現自動的轉換,他還需要一系列的字元定義支援。
1. TCHAR
如果定義了UNICODE巨集則TCHAR被定義為wchar_t。
typedef wchar_t TCHAR;
   否則TCHAR被定義為char typedef char TCHAR;
2. LPTSTR
   如果定義了UNICODE巨集則LPTSTR被定義為LPWSTR。
   typedef LPTSTR LPWSTR;
   否則TCHAR被定義為char typedef LPTSTR LPSTR;
   說明:在使用字串常量的時候需要使用_TEXT(“MyStr”)或者_T("")來支援系統的自動轉換。

3.BSTR

   BSTR是一個帶長度字首的字串,主要由作業系統來管理的,所以要用api.主要用來和VB打交道的(VB裡的string就是指它)要操作它的API函式有很多.比如SysAllocString,SysFreeString等等.
   vc裡封裝它的類如_bstr_t,及ATL中的CComBSTR等.
   一個 BSTR 由頭部和字串組成,頭部包含了字串的長度資訊,字串中可以包含嵌入的 null 值。
   BSTR 是以指標的形式進行傳遞的。(指標是一個變數,包含另外一個變數的記憶體地址,而不是資料。) BSTR 是 Unicode 的,即每個字元需要兩個位元組。 BSTR 通常以兩位元組的 null 字元結束。 wstr是寬字元,以雙位元組表示一個字元 bstr是為了與原先的basic字元相容,它的最前面的4個位元組為其長度,以'\0'結束.

4.更進一步的字串以及其指標的型別定義 

由於Win32 API文件的函式列表使用函式的常用名字(例如, "SetWindowText"),所有的字串都是用TCHAR來定義的。(除了XP中引入的只適用於Unicode的API)。下面列出一些常用的typedefs,你可以在msdn中看到他們。

type    Meaning in MBCS builds    Meaning in Unicode builds
WCHAR    wchar_t    wchar_t
LPSTR    char*    char*
LPCSTR    const char*    const char*
LPWSTR    wchar_t*    wchar_t*
LPCWSTR    wchar_t*    wchar_t*
TCHAR    TCHAR char    wchar_t
LPTSTR    TCHAR*    TCHAR*
LPCTSTR    const TCHAR*    const TCHAR*

5.相互轉換

(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);

=====================================================================

轉自:

http://www.cnblogs.com/chenleiustc/archive/2011/04/09/2010647.html

根據ANSI C標準的賦值約束條件:

    1. 兩個運算元都是指向有限定符或無限定符的相容型別的指標。

    2. 左邊指標所指向的型別必須具有右邊指標所指向型別的全部限定符。

一、const char*和char*

    const char*的型別是:“指向一個具有const限定符的char型別的指標”。(不能修改其值)

    char*的型別是:“指向一個char型別的指標”。

    因此const char*和char*都是指向char型別的指標,只不過const char*指向的char型別是const的。

    因此對於程式碼:

char* src; 
const char* dest ; 
dest = src;

    這樣賦值是正確的,因為:

    * 運算元指向的都是char型別,因此是相容的

    * 左運算元具有有運算元所指向型別的全部限定符(右運算元沒有限定符),同時自己有限定符(const)

    如果反過來賦值就違反了賦值的約束條件:src指向的物件的值可以修改,而dest指向的物件的值不可修改
如果讓src去指向dest所指向的那個不可修改的物件,如果合法,豈不是變得可修改了?

src = dest; // 這樣賦值,左運算元指向的型別沒有右運算元指向型別的const限定符,不符合約束條件2


2. const char** 和char**

    const char**的型別是:“指向一個有const限定符的char型別的指標的指標”。

    char**的型別是:“指向一個char型別的指標的指標”。

    對於const char** 和char**來說,二者都是沒有限定符的指標型別,但是它們指向的型別不一樣,前者指向char*,    而後者指向const char*,因此它們不相容,所以char**型別的運算元不能賦值給const char**型別的運算元。

    即對於下列程式碼,編譯器會報錯:char** src; 
const char** dest; 
dest = src; 
// error: invalid conversion from `char**' to `const char**' 
-------------------------------------------------------------------------------------------------------------

const
1. 限定符宣告變數只能被讀
   const int i=5;
   int j=0;
   ...
   i=j;   //非法,導致編譯錯誤
   j=i;   //合法
2. 必須初始化
   const int i=5;    //合法
   const int j;      //非法,導致編譯錯誤
3. 在另一連線檔案中引用const常量
   extern const int i;     //合法
   extern const int j=10; //非法,常量不可以被再次賦值
4. 便於進行型別檢查
   用const方法可以使編譯器對處理內容有更多瞭解。
   #define I=10
   const long &i=10;   /*dapingguo提醒:由於編譯器的優化,使得在const long i=10; 時i不被分配記憶體,而是已10直接代入 以後的引用中,以致在以後的程式碼中沒有錯誤,為達到說教效 果,特別地用&i明確地給出了i的記憶體分配。 不過一旦你關閉所 有優化措施,即使const long i=10;也會引起後面的編譯錯誤。*/
   char h=I;      //沒有錯
   char h=i;      //編譯警告,可能由於數的截短帶來錯誤賦值。
5. 可以避免不必要的記憶體分配
   #define STRING "abcdefghijklmn\n"
   const char string[]="abcdefghijklm\n";
   ...
   printf(STRING);   //為STRING分配了第一次記憶體
   printf(string);   //為string一次分配了記憶體,以後不再分配
   ...
   printf(STRING);   //為STRING分配了第二次記憶體
   printf(string);
   ... 
   由於const定義常量從彙編的角度來看,只是給出了對應的記憶體地址,
   而不是象#define一樣給出的是立即數,所以,const定義的常量在
   程式執行過程中只有一份拷貝,而#define定義的常量在記憶體中有
   若干個拷貝。
6. 可以通過函式對常量進行初始化
   int value(); 
   const int i=value();
   dapingguo說:假定對ROM編寫程式時,由於目的碼的不可改寫,本語句將會無效,不過可以變通一下:
   const int &i=value();
   只要令i的地址處於ROM之外,即可實現:i通過函式初始化,而其值有不會被修改。
7. 是不是const的常量值一定不可以被修改呢?
   觀察以下一段程式碼:
   const int i=0;
   int *p=(int*)&i;
   p=100;
   通過強制型別轉換,將地址賦給變數,再作修改即可以改變const常量值。
8. 請分清數值常量和指標常量,以下宣告頗為玩味:
   int ii=0;
   const int i=0;            //i是常量,i的值不會被修改
   const int *p1i=&i;        //指標p1i所指內容是常量,可以不初始化
   int * const p2i=&ii;     //指標p2i是常量,所指內容可修改
   const int * const p3i=&i; //指標p3i是常量,所指內容也是常量
   p1i=&ii;                  //合法
   *p2i=100;                 //合法

關於C++中的const關鍵字的用法非常靈活,而使用const將大大改善程式的健壯性,參考了康建東兄的const使用詳解一文,對其中進行了一些補充,寫下了本文。
1.       const常量,如const int max = 100; 
優點:const常量有資料型別,而巨集常量沒有資料型別。編譯器可以對前者進行型別安全檢查,而對後者只進行字元替換,沒有型別安全檢查,並且在字元替換時可能會產生意料不到的錯誤(邊際效應)

2.       const 修飾類的資料成員。如:
class A
{   

const int size;

    … }


const資料成員只在某個物件生存期內是常量,而對於整個類而言卻是可變的。因為類可以建立多個物件,不同的物件其const資料成員的值可以不同。所以不能在類宣告中初始化const資料成員,因為類的物件未被建立時,編譯器不知道const 資料成員的值是什麼。如
class A
{
const int size = 100;    //錯誤
int array[size];         //錯誤,未知的size
}

const資料成員的初始化只能在類的建構函式的初始化表中進行。要想建立在整個類中都恆定的常量,應該用類中的列舉常量來實現。如
class A
{…
enum {size1=100, size2 = 200 };
int array1[size1];
int array2[size2]; 
}

列舉常量不會佔用物件的儲存空間,他們在編譯時被全部求值。但是列舉常量的隱含資料型別是整數,其最大值有限,且不能表示浮點數。

3.       const修飾指標的情況,見下式:
int b = 500; 
const int* a = &           [1] 
int const *a = &           [2] 
int* const a = &           [3] 
const int* const a = &     [4]

如果你能區分出上述四種情況,那麼,恭喜你,你已經邁出了可喜的一步。不知道,也沒關係,我們可以參考《Effective c++》Item21上的做法,如果const位於星號的左側,則const就是用來修飾指標所指向的變數,即指標指向為常量;如果const位於星號的 右側,const就是修飾指標本身,即指標本身是常量。因此,[1]和[2]的情況相同,都是指標所指向的內容為常量(const放在變數宣告符的位置無 關),這種情況下不允許對內容進行更改操作,如不能*a = 3 ;[3]為指標本身是常量,而指標所指向的內容不是常量,這種情況下不能對指標本身進行更改操作,如a++是錯誤的;[4]為指標本身和指向的內容均為常 量。

4.     const的初始化

先看一下const變數初始化的情況 
1) 非指標const常量初始化的情況:A b; 
const A a = b;

2) 指標const常量初始化的情況:
A* d = new A(); 
const A* c = d; 
或者:const A* c = new A(); 
3)引用const常量初始化的情況: 
A f; 
const A& e = f;      // 這樣作e只能訪問宣告為const的函式,而不能訪問一           


般的成員函式;

    [思考1]: 以下的這種賦值方法正確嗎? 
    const A* c=new A(); 
    A* e = c; 
    [思考2]: 以下的這種賦值方法正確嗎? 
    A* const c = new A(); 
    A* b = c;


5.     另外const 的一些強大的功能在於它在函式宣告中的應用。在一個函式宣告中,const 可以修飾函式的返回值,或某個引數;對於成員函式,還可以修飾是整個函式。有如下幾種情況,以下會逐漸的說明用法:A& operator=(const A& a); 
void fun0(const A* a ); 
void fun1( ) const; // fun1( ) 為類成員函式 
const A fun2( );


1) 修飾引數的const,如 void fun0(const A* a ); void fun1(const A& a); 
調 用函式的時候,用相應的變數初始化const常量,則在函式體中,按照const所修飾的部分進行常量化,如形參為const A* a,則不能對傳遞進來的指標的內容進行改變,保護了原指標所指向的內容;如形參為const A& a,則不能對傳遞進來的引用物件進行改變,保護了原物件的屬性。 
[注意]:引數const通常用於引數為指標或引用的情況,且只能修飾輸入引數;若輸入引數採用“值傳遞”方式,由於函式將自動產生臨時變數用於複製該引數,該引數本就不需要保護,所以不用const修飾。


[總結]對於非內部資料型別的輸入引數,因該將“值傳遞”的方式改為“const引用傳遞”,目的是為了提高效率。例如,將void Func(A a)改為void Func(const A &a)
      對於內部資料型別的輸入引數,不要將“值傳遞”的方式改為“const引用傳遞”。否則既達不到提高效率的目的,又降低了函式的可理解性。例如void Func(int x)不應該改為void Func(const int &x)


2) 修飾返回值的const,如const A fun2( ); const A* fun3( ); 
這樣聲明瞭返回值後,const按照"修飾原則"進行修飾,起到相應的保護作用。const Rational operator*(const Rational& lhs, const Rational& rhs) 

return Rational(lhs.numerator() * rhs.numerator(), 
lhs.denominator() * rhs.denominator()); 
}

返回值用const修飾可以防止允許這樣的操作發生:Rational a,b; 
Radional c; 
(a*b) = c;

一般用const修飾返回值為物件本身(非引用和指標)的情況多用於二目操作符過載函式併產生新物件的時候。 [總結]


1.     一般情況下,函式的返回值為某個物件時,如果將其宣告為const時,多用於操作符的過載。通常,不建議用const修飾函式的返回值型別為某個物件或對 某個物件引用的情況。原因如下:如果返回值為某個物件為const(const A test = A 例項)或某個物件的引用為const(const A& test = A例項) ,則返回值具有const屬性,則返回例項只能訪問類A中的公有(保護)資料成員和const成員函式,並且不允許對其進行賦值操作,這在一般情況下很少 用到。


2.       如果給採用“指標傳遞”方式的函式返回值加const修飾,那麼函式返回值(即指標)的內容不能被修改,該返回值只能被賦給加const 修飾的同類型指標。如:


const char * GetString(void);


如下語句將出現編譯錯誤:


char *str=GetString();


正確的用法是:


const char *str=GetString();


3.     函式返回值採用“引用傳遞”的場合不多,這種方式一般只出現在類的賻值函式中,目的是為了實現鏈式表達。如:


class A
{…
A &operate = (const A &other); //負值函式
}
A a,b,c;              //a,b,c為A的物件

a=b=c;            //正常
(a=b)=c;          //不正常,但是合法


若負值函式的返回值加const修飾,那麼該返回值的內容不允許修改,上例中a=b=c依然正確。(a=b)=c就不正確了。
[思考3]: 這樣定義賦值操作符過載函式可以嗎? 
const A& operator=(const A& a);


6.     類成員函式中const的使用 
一般放在函式體後,形如:void fun() const; 
任何不會修改資料成員的函式都因該宣告為const型別。如果在編寫const成員函式時,不慎修改了資料成員,或者呼叫了其他非const成員函式,編譯器將報錯,這大大提高了程式的健壯性。如:


class Stack
{
public:
      void Push(int elem);
      int Pop(void);

      int GetCount(void) const;   //const 成員函式
private: 
      int m_num;
      int m_data[100];
};


int Stack::GetCount(void) const

{
++m_num;              //編譯錯誤,企圖修改資料成員m_num
Pop();                    //編譯錯誤,企圖呼叫非const函式
Return m_num;
}


7.       使用const的一些建議

1 要大膽的使用const,這將給你帶來無盡的益處,但前提是你必須搞清楚原委; 
2 要避免最一般的賦值操作錯誤,如將const變數賦值,具體可見思考題; 
3 在引數中使用const應該使用引用或指標,而不是一般的物件例項,原因同上; 
4 const在成員函式中的三種用法(引數、返回值、函式)要很好的使用; 
5 不要輕易的將函式的返回值型別定為const; 
6除了過載操作符外一般不要將返回值型別定為對某個物件的const引用;

[思