vc++中各種字符串(轉載)
http://www.cnblogs.com/tomin/archive/2008/12/28/1364097.html
CString ,BSTR ,LPCTSTR之間關系和區別
CString是一個動態TCHAR數組,BSTR是一種專有格式的字符串(需要用系統提供的函數來操縱,LPCTSTR只是一個常
量的TCHAR指針。
CString 是一個完全獨立的類,動態的TCHAR數組,封裝了 + 等操作符和字符串操作方法。
typedef OLECHAR FAR* BSTR;
typedef const char * LPCTSTR;
vc++中各種字符串的表示法
首先char* 是指向ANSI字符數組的指針,其中每個字符占據8位(有效數據是除掉最高位的其他7位),這里保持了與傳
統的C,C++的兼容。
LP的含義是長指針(long pointer)。LPSTR是一個指向以‘\0’結尾的ANSI字符數組的指針,與char*可以互換使用,在
win32中較多地使用LPSTR。
而LPCSTR中增加的‘C’的含義是“CONSTANT”(常量),表明這種數據類型的實例不能被使用它的API函數改變,
除此之外,它與LPSTR是等同的。
1.LP表示長指針,在win16下有長指針(LP)和短指針(P)的區別,而在win32下是沒有區別的,都是32位.所以這里的LP和P是等
價的.
2.C表示const
3.T是什么東西呢,我們知道TCHAR在采用Unicode方式編譯時是wchar_t,在普通時編譯成char.
為了滿足程序代碼國際化的需要,業界推出了Unicode標准,它提供了一種簡單和一致的表達字符串的方法,所有字符
中的字節都是16位的值,其數量也可以滿足差不多世界上所有書面語言字符的編碼需求,開發程序時使用Unicode(類
型為wchar_t)是一種被鼓勵的做法。
LPWSTR與LPCWSTR由此產生,它們的含義類似於LPSTR與LPCSTR,只是字符數據是16位的wchar_t而不是char。
然后為了實現兩種編碼的通用,提出了TCHAR的定義:
如果定義_UNICODE,聲明如下:
typedef wchar_t TCHAR;
如果沒有定義_UNICODE,則聲明如下:
typedef char TCHAR;
LPTSTR和LPCTSTR中的含義就是每個字符是這樣的TCHAR。
CString類中的字符就是被聲明為TCHAR類型的,它提供了一個封裝好的類供用戶方便地使用。
LPCTSTR:
#ifdef _UNICODE
typedef const wchar_t * LPCTSTR;
#else
typedef const char * LPCTSTR;
#endif
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);
二、從其它包含字符串的變量中獲取指向該字符串的指針
CString變量
str = "2008北京奧運";
buf = (LPSTR)(LPCTSTR)str;
BSTR類型的_variant_t變量
v1 = (_bstr_t)"程序員";
buf = _com_util::ConvertBSTRToString((_bstr_t)v1);
三、字符串轉換為其它數據類型
strcpy(temp,"123");
短整型(int)
i = atoi(temp);
長整型(long)
l = atol(temp);
浮點(double)
d = atof(temp);
四、其它數據類型轉換到CString
使用CString的成員函數Format來轉換,例如:
整數(int)
str.Format("%d",i);
浮點數(float)
str.Format("%f",i);
字符串指針(char *)等已經被CString構造函數支持的數據類型可以直接賦值
str = username;
五、BSTR、_bstr_t與CComBSTR
CComBSTR、_bstr_t是對BSTR的封裝,BSTR是指向字符串的32位指針。
char *轉換到BSTR可以這樣: BSTR b=_com_util::ConvertStringToBSTR("數據"); //使用前需要加上頭文件
comutil.h
反之可以使用char *p=_com_util::ConvertBSTRToString(b);
六、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與常用數據的對應關系:
unsigned char 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
IUnknown FAR* punkVal; VT_UNKNOWN
IDispatch FAR* pdispVal; VT_DISPATCH
SAFEARRAY FAR* parray; VT_ARRAY|*
unsigned char 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; VT_BYREF
_variant_t是VARIANT的封裝類,其賦值可以使用強制類型轉換,其構造函數會自動處理這些數據類型。
例如:
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;
七、其它
對消息的處理中我們經常需要將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位
如何將CString類型的變量賦給char*類型的變量
1、GetBuffer函數:
使用CString::GetBuffer函數。
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(int n),其中n為我們需要的字符數組的長度.使用完成后一定要馬上調用
ReleaseBuffer();
還有很重要的一點就是,在能使用const char *的地方,就不要使用char *
2、memcpy:
CString mCS=_T("cxl");
char mch[20];
memcpy(mch,mCS,20);
3、用LPCTSTR強制轉換: 盡量不使用
char *ch;
CString str;
ch=(LPSTR)(LPCTSTR)str;
CString str = "good";
char *tmp;
sprintf(tmp,"%s",(LPTSTR)(LPCTSTR)str);
4、
CString Msg;
Msg=Msg+"abc";
LPTSTR lpsz;
lpsz = new TCHAR[Msg.GetLength()+1];
_tcscpy(lpsz, Msg);
char * psz;
strcpy(psz,lpsz);
CString類向const char *轉換
char a[100];
CString str("aaaaaa");
strncpy(a,(LPCTSTR)str,sizeof(a));
或者如下:
strncpy(a,str,sizeof(a));
以上兩種用法都是正確地. 因為strncpy的第二個參數類型為const char *.所以編譯器會自動將CString類轉換成const
char *.
CString轉LPCTSTR (const char *)
CString cStr;
const char *lpctStr=(LPCTSTR)cStr;
LPCTSTR轉CString
LPCTSTR lpctStr;
CString cStr=lpctStr;
將char*類型的變量賦給CString型的變量
可以直接賦值,如:
CString myString = "This is a test";
也可以利用構造函數,如:
CString s1("Tom");
將CString類型的變量賦給char []類型(字符串)的變量
1、sprintf()函數
CString str = "good";
char tmp[200] ;
sprintf(tmp, "%s",(LPCSTR)str);
(LPCSTR)str這種強制轉換相當於(LPTSTR)(LPCTSTR)str
CString類的變量需要轉換為(char*)的時,使用(LPTSTR)(LPCTSTR)str
然而,LPCTSTR是const char *,也就是說,得到的字符串是不可寫的!將其強制轉換成LPTSTR去掉const,是極為危險
的!
一不留神就會完蛋!要得到char *,應該用GetBuffer()或GetBufferSetLength(),用完后再調用ReleaseBuffer()。
2、strcpy()函數
CString str;
char c[256];
strcpy(c, str);
char mychar[1024];
CString source="Hello";
strcpy((char*)&mychar,(LPCTSTR)source);
關於CString的使用
1、指定 CString 形參
對於大多數需要字符串參數的函數,最好將函數原型中的形參指定為一個指向字符 (LPCTSTR) 而非 CString 的
const 指針。
當將形參指定為指向字符的 const 指針時,可將指針傳遞到 TCHAR 數組(如字符串 ["hi there"])或傳遞到 CString
對象。
CString 對象將自動轉換成 LPCTSTR。任何能夠使用 LPCTSTR 的地方也能夠使用 CString 對象。
2、如果某個形參將不會被修改,則也將該參數指定為常數字符串引用(即 const CString&)。如果函數要修改該字符
串,
則刪除 const 修飾符。如果需要默認為空值,則將其初始化為空字符串 [""],如下所示:
void AddCustomer( const CString& name, const CString& address, const CString& comment = "" );
3、對於大多數函數結果,按值返回 CString 對象即可。
串的基本運算
對於串的基本運算,很多高級語言均提供了相應的運算符或標准的庫函數來實現。
為敘述方便,先定義幾個相關的變量:
char s1[20]="dir/bin/appl",s2[20]="file.asm",s3[30],*p;
int result;
下面以C語言中串運算介紹串的基本運算
1、求串長
int strlen(char *s); //求串s的長度
【例】printf("%d",strlen(s1)); //輸出s1的串長12
2、串復制
char *strcpy(char *to,*from);//將from串復制到to串中,並返回to開始處指針
【例】strcpy(s3,s1); //s3="dir/bin/appl",s1串不變
3、聯接
char *strcat(char *to,char *from);//將from串復制到to串的末尾,
//並返回to串開始處的指針
【例】strcat(s3,"/"); //s3="dir/bin/appl/"
strcat(s3,s2); //s3="dir/bin/appl/file.asm"
4、串比較
int strcmp(char *s1,char *s2);//比較s1和s2的大小,
//當s1<s2、s1>s2和s1=s2時,分別返回小於0、大於0和等於0的值
【例】result=strcmp("baker","Baker"); //result>0
result=strcmp("12","12"); //result=0
result=strcmp("Joe","joseph") //result<0
5、字符定位
char *strchr(char *s,char c);//找c在字符串s中第一次出現的位置,
//若找到,則返回該位置,否則返回NULL
【例】p=strchr(s2,'.'); //p指向"file"之后的位置
if(p) strcpy(p,".cpp"); //s2="file.cpp"
注意:
①上述操作是最基本的,其中后 4個操作還有變種形式:strncpy,strncath和strnchr。
②其它的串操作見C的<string.h>。在不同的高級語言中,對串運算的種類及符號都不盡相同
③其余的串操作一般可由這些基本操作組合而成
【例】求子串的操作可如下實現:
void substr(char *sub,char *s,int pos,int len){
//s和sub是字符數組,用sub返回串s的第pos個字符起長度為len的子串
//其中0<=pos<=strlen(s)-1,且數組sub至少可容納len+1個字符。
if (pos<0||pos>strlen(s)-1||len<0)
Error("parameter error!");
strncpy(sub,&s[pos],len); //從s[pos]起復制至多len個字符到sub
========
vc++中各種字符串的表示法
http://blog.csdn.net/kybd2006/article/details/1566827
首先char* 是指向ANSI字符數組的指針,其中每個字符占據8位(有效數據是除掉最高位的其他7位);
LP的含義是長指針(long pointer)。LPSTR是一個指向以‘/0’結尾的ANSI字符數組的指針,與char*可以互換使
用,在win32中較多地使用LPSTR(並且長指針(LP)和短指針(P)是等價的)。而LPCSTR中增加的‘C’的含義
是“CONSTANT”(常量),表明這種數據類型的實例不能被使用它的API函數改變,除此之外,它與LPSTR是等同的
。
我們知道TCHAR在采用Unicode方式編譯時是wchar_t,在普通時編譯成char,業界推出的Unicode標准,它提供
了一種簡單和一致的表達字符串的方法,所有字符中的字節都是16位的值,其數量也可以滿足差不多世界上所有書面語
言字符的編碼需求,開發程序時使用Unicode(類型為wchar_t)是一種被鼓勵的做法。LPWSTR與LPCWSTR由此產生,
它們的含義類似於LPSTR與LPCSTR,只是字符數據是16位的wchar_t而不是char。
然后為了實現兩種編碼的通用,提出了TCHAR的定義:
如果定義_UNICODE,聲明如下:
typedef wchar_t TCHAR;
如果沒有定義_UNICODE,則聲明如下:
typedef char TCHAR;
LPTSTR和LPCTSTR中的含義就是每個字符是這樣的TCHAR。
CString類中的字符就是被聲明為TCHAR類型的,它提供了一個封裝好的類供用戶方便地使用。
LPCTSTR:
#ifdef _UNICODE
typedef const wchar_t * LPCTSTR;
#else
typedef const char * LPCTSTR;
#endif
========
vc++下的字符串處理
http://blog.chinaunix.net/uid-192452-id-3182259.html
07年在啟明做個專題的講座,現在提煉升華一下。
vc工程中考慮到UNICODE的設置問題,盡可能使用三種字符串,ATL的CString,不是mfc的CString,使用com 就使用
CComBSTR,使用api的話,盡可能用TCHAR,字符串操作盡可能用_tcs函數。
除非考慮跨平台,否則不要使用stl的string,應該使用CString,雖然可以使用如下設置
#include
using namespace std;
#ifndef UNICODE
typedef string TSTRING;
#else
typedef wstring TSTRING;
#endif
使用stl的string 以后的字符串操作會很復雜,
例如得到程序當前的路徑
TCHAR buffer[MAX_PATH+1];
DWORD iNombreChars = GetCurrentDirectory(MAX_PATH, buffer);
string strPath;
strPath.assign(&buffer[0], &buffer[iNombreChars]);
這是閑的蛋疼
也有簡單的,
std::string str(MAX_PATH+1, 0);
GetCurrentDirectory(MAX_PATH, &str[0]);
將string轉為TCHAR
TCHAR *param=new TCHAR[tsDir.size()+1];
param[tsDir.size()]=_T('\0');
//As much as we'd love to, we can't use memcpy() because
//sizeof(TCHAR)==sizeof(char) may not be true:
std::copy(tsDir.begin(),tsDir.end(),param);
如果經常轉換,最后會抓狂的。
========
返璞歸真vc++之字符類型
http://www.cnblogs.com/lichaoxyz/p/3636906.html
在今天,大量使用java與.net的程序員已經很少去真實了解字符的底層表達,但是使用VC++編程,對字符的處理卻
非常慎重,剛學習vc++肯定會為其中的字符類型給暈頭轉向,今天本人學習第一節,從字符開始
特別說明:本文章所有開發環境選用vs2012開發
在計算機系統中所有的數據與程序指令都是二進制的形式存在的,CPU處理器給特定序列的二進制序列包含有特殊
的意義,及我們常說的計算機指令,計算機指令目前流行的X86指令集,以及目前流行android平台下arm指令集,同時
所有的數據也是以二進制的形式表達在計算機中,主要表達在計算機體系中的內存,寄存器,以及CPU緩存。所以計算
機認識到的字符也就是一串二進制格式的數據,計算機的首要任務就是給這些二進制進行字符的映射,但是在不同的指
令集與CPU下,對這些二進制進行翻譯的過程中又產生了高位與低位只說,這個只是CPU級別的二進制讀取順序,如何
給這些特定的二進制翻譯成我們熟悉的人類語言,於是就產生了我們經常所說的字符串編碼,常用的有ASCII編碼,以及
Unicode,
asccii編碼,及單個字節編碼,1個字節8個位,也就是說,在計算機內存中,8個連續的位能代碼一個字符,那么如
何映射成字符呢,那么就是通過我們的assicc表來實現,如下
八進制 十六進制 十進制 字符 八進制 十六進制 十進制 字符
00 00 0 nul 100 40 64 @
01 01 1 soh 101 41 65 A
02 02 2 stx 102 42 66 B
03 03 3 etx 103 43 67 C
04 04 4 eot 104 44 68 D
05 05 5 enq 105 45 69 E
06 06 6 ack 106 46 70 F
07 07 7 bel 107 47 71 G
10 08 8 bs 110 48 72 H
11 09 9 ht 111 49 73 I
12 0a 10 nl 112 4a 74 J
13 0b 11 vt 113 4b 75 K
14 0c 12 ff 114 4c 76 L
15 0d 13 cr 115 4d 77 M
16 0e 14 so 116 4e 78 N
17 0f 15 si 117 4f 79 O
20 10 16 dle 120 50 80 P
21 11 17 dc1 121 51 81 Q
22 12 18 dc2 122 52 82 R
23 13 19 dc3 123 53 83 S
24 14 20 dc4 124 54 84 T
25 15 21 nak 125 55 85 U
26 16 22 syn 126 56 86 V
27 17 23 etb 127 57 87 W
30 18 24 can 130 58 88 X
31 19 25 em 131 59 89 Y
32 1a 26 sub 132 5a 90 Z
33 1b 27 esc 133 5b 91 [
34 1c 28 fs 134 5c 92 \
35 1d 29 gs 135 5d 93 ]
36 1e 30 re 136 5e 94 ^
37 1f 31 us 137 5f 95 _
40 20 32 sp 140 60 96 '
41 21 33 ! 141 61 97 a
42 22 34 " 142 62 98 b
43 23 35 # 143 63 99 c
44 24 36 $ 144 64 100 d
45 25 37 % 145 65 101 e
46 26 38 & 146 66 102 f
47 27 39 ` 147 67 103 g
50 28 40 ( 150 68 104 h
51 29 41 ) 151 69 105 i
52 2a 42 * 152 6a 106 j
53 2b 43 + 153 6b 107 k
54 2c 44 , 154 6c 108 l
55 2d 45 - 155 6d 109 m
56 2e 46 . 156 6e 110 n
57 2f 47 / 157 6f 111 o
60 30 48 0 160 70 112 p
61 31 49 1 161 71 113 q
62 32 50 2 162 72 114 r
63 33 51 3 163 73 115 s
64 34 52 4 164 74 116 t
65 35 53 5 165 75 117 u
66 36 54 6 166 76 118 v
67 37 55 7 167 77 119 w
70 38 56 8 170 78 120 x
71 39 57 9 171 79 121 y
72 3a 58 : 172 7a 122 z
73 3b 59 ; 173 7b 123 {
74 3c 60 < 174 7c 124 |
75 3d 61 = 175 7d 125 }
76 3e 62 > 176 7e 126 ~
77 3f 63 ? 177 7f 127 del
其中,每一個二進制序列對應這一個英文與數字字符,例如常說的十進制數65的二進制表達是1000001,對應的十六進制
為0x41;
我們都知道c語言中,字符是用char類型表示,同時默認的編碼格式為asccii編碼,也就是說當0x41這個十六進制數在轉
換成整形值是65,在進行asccii字符轉換時,如上表所示,即我們常說的大寫字母A,
下面我們做一個實驗,即可證明以上觀點是否正確
#include "stdafx.h"
int _tmain(int argc, _TCHAR* argv[])
{
//數值數據
int i=0x41;
//內存數據按整形值翻譯打印出來
printf("this is int%d\n",i);
//內存數據按照asccii翻譯打印出來
printf("this is char%c\n",i);
//打印出內存數據的十六進制格式
printf("this is binary 0x%x\n",i);
return 0;
}
復制代碼
打印結果如下
由此可見,數據的表達都是二進制,只是人為的定義了一些一些含義,你認為是字符的時候,就轉換成字符,你認為是
數字的時候就變成了數字,你認為是指令的時候,就編程了是指令,只是指令已經被CPU確定了含義。
那么同理得出Unicode也是類似的結構,只是有點不同
1、Unicode為雙字節編碼,也就是說一個字符需要兩個字節的容量才能保存
所以需要特別注意的地方到了,那么以上這些函數printf能處理Unicode字符串嗎?
答案顯然是不能的,我們依然寫一個程序去驗證我們的結果
#include "stdafx.h"
#include <Windows.h>
int _tmain(int argc, _TCHAR* argv[])
{
WCHAR unicodeChar='很';
printf("this is unicode Char%c\n",unicodeChar);
return 0;
}
打印的結論:
可以看到,最終被一個問號代替了,也就是說,printf函數並沒有把他解析出來,它依然按照asccii標准去解析,所以變
成了問號,那么疑問出來了
WCHAR到底是一個什么類型呢,怎么在c++標准中並不存在這樣一個類型呢?
答案馬上揭曉,我們找到了下面的宏定義
#ifndef _MAC //非蘋果硬件平台
typedef wchar_t WCHAR; //實際值是wchar_t // wc, 16-bit UNICODE character
#else
// some Macintosh compilers don't define wchar_t in a convenient location, or define it as a char
typedef unsigned short WCHAR; //蘋果硬件平台實際上是unsigned short
// wc, 16-bit UNICODE character #endif
也就是如上所述:
所以在我們常用的電腦下,都是wchar_t類型,那么這又是一個什么類型呢?
百度百科給出的定義如下,http://baike.baidu.com/link?
url=s9f5p8uJEuzVarbu0ilC2XTNRSEQHmxMM0pAHJE5w-Iysq2KFAmRXQUqSuYbbIF-AwmC0e_-
Rtsy9NUKP6QVYK
char是8位字符類型,最多只能包含256種字符,許多外文字符集所含的字符數目超過256個,char型無法表示。
wchar_t數據類型一般為16位或32位,但不同的C或C++庫有不同的規定,如GNU Libc規定wchar_t為32位[1],總之,
wchar_t所能表示的字符數遠超char型。
標准C++中的wprintf()函數以及iostream類庫中的類和對象能提供wchar_t寬字符類型的相關操作。
所以是一個寬字符,也就是比char類型大,支持多種語言,比如東南亞國家的語言等,所以我認為在后續的編程中,應
該盡可能的使用寬字符類型,同時對於寬字符類型,c++標准也提供了wprintf一系列類來操作
今天就是以上學習的內容啦,大概就這么多了,通過理解原理,然后去看vc++對這些類型的宏包裝,其中不同類型的相
互轉換應該也是有所理解的。