程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> Visual Basic語言 >> VB.NET >> API入門系列之三 -那迷惑人的Windows字符和字符指針類型

API入門系列之三 -那迷惑人的Windows字符和字符指針類型

編輯:VB.NET

大家好,通過前面兩篇打頭文章,我也看了留言,感謝那些給我提意見的人和指出錯誤之處的人。再次謝謝你們的支持。另外,Windows SDK編程交流群已經建立了,歡迎各位志同道合者加入進行交流(群號:81543028)

本打算通過前面兩篇文章的講解,後來的系列就可以通過使用一些簡單的,常用的API寫一些示例程序的講解進行,但是發現還有一個不得不先講一講的要點,Windows下和字符串操作有關的數據類型。我看留言中也有幾位朋友提到了,那我就在這篇中講它吧。不會很枯燥的,各位慢慢看下去就是了。

下面我羅列一些我們在Windows平台下編程經常使用到的和字符或字符串有關的數據類型。

char和wchar_t

這兩個類型大家絕對不會陌生吧,一個是單字節的字符類型,一個是寬字節的字符類型(也就是 Unicode字符)。

char   c = 'b';

wcha_t  wc = L'b';

上面我就分別定義了2個變量c和wc ,相信第一個定義大家都看的懂,就是定一個字符變量c,其中 保存了'b'這個字符。那麼第二個呢?  我相信還是很多人都看的懂,要是你看不懂也沒關 系,現在就告訴你,也是定義一個字符變量wc, 只不過這個字符變量是Unicode字符變量,用2個字節 來保存一個字符,而上面的c這個字符變量只有一個字節來保存,那麼在'b'前面的L又是什麼意 思呢,它就表示這裡的'b'這個字符是一個Unicode字符,所以第二個定義的意思就是將 L'b'這個Unicode字符保存到wc這個Unicode字符變量中。

如果我要定義一個字符數組怎麼定 義呢? 用分別用單字節的char和寬字節的wchar_t來定義就應該是:

char  c[10];

wchar_t wc[10];

如果是要帶初始化的字符數組的聲明,我們來看看怎麼寫

char c[] = "beyondcode";

wchar_t wc[] = L"beyondcode";

看到了嗎,寬字節的操作其實和單字節的字符操作一樣吧,只是在前面加上L表示是寬字節的字符或 者字符串。

上面都是屬於C/C++中的知識,並沒有涉及太多Windows中的數據類型,那麼各位朋友們在Windows編 程中看到的滿到處都是的 TCHAR,LPSTR, LPCSTR, LPWSTR, LPCWSTR, LPTSTR, LPCTSTR 這些數 據類型又是怎麼回事呢? 別急,我們一步一步的來,最後我會聯系到那上面去的。

上面的你都知道或者是理解了的話,那我們繼續,除了可以聲明一個字符數組,我還可以定義一個字 符指針變量來指向一個字符數組,當然這個字符數組可以是Unicode的寬字節字符數組,也可以是單字節 字符數組,如下:

char  c[] = "hello beyondcode"; //定義一個字符數組

wchar_t  wc[] = L"hello beyondcode"; //定義一個寬字節字符數組

char   *p = c; //定義一個字符指針,指向剛才的字符數組

wchar_t *wp = wc; //定義一個寬字節字符指針,指向剛才的寬字節字符數組

這樣之後,我就可以通過指針來改變剛才我們定義的2個數組,例如:

p[0] =  'H';

wp[0] = L'H';

把上面2個數組的第一個字符通過指針改變成大寫。這裡是可以通過指針來修改的,因為我沒有定義 指針為常量指針,也就是沒有加const 修飾符。如果我像下面這樣定義的話,那麼就不能通過這些指針 來改變他們所指向的數據了,而是只有讀取他們。

const  char  *p = c;

const  wchar_t  *wp = wc;

上面將的都是C/C++的基礎知識,有點啰嗦,為了照顧新手朋友們嘛,下面我們就來看看Windows是怎 麼定義它的數據類型的

首先,定義了CHAR, WCHAR的這2個字符數據類型,就是我們上面討論的兩個字符數據類型改了一下 名字而已。現在你還不昏吧··

typedef char  CHAR;

typedef wchar_t  WCHAR;

然後,用剛才定義的 CHAR, WCHAR這2個字符數據類型去定義了一系列其他字符指針類型。

typedef  CHAR  *LPSTR;

typedef  WCHAR  *LPWSTR;

這樣一定義之後,LPSTR的就是 CHAR*, 而CHAR 又是char, 所以LPSTR的本質就是 char*,也 就是我們上面熟悉的不能再熟悉的字符指針,  那LPWSTR不用我推導,相信你也推導出來了吧。不過我 還是推導一下,LPWSTR是 WCHAR * , WCHAR是wchar_t,這樣LPWSTR就是 wchar_t* ,也就是我 們上面討論的寬字節字符指針。上面這些定義都是在WinNT.h這個頭文件中定義的,讀者朋友們有興趣在 這個頭文件裡面去挖掘挖掘吧,上面2個定義我只是提取了重要的部分,其實在裡面他還定義了其他很多 別名.

看了LPSTR, LPWSTR是怎麼一回事之後,我們再接再厲,看看LPCSTR,LPCWSTR這2個數據類型又 是怎麼一回事呢, 老規矩,先看windows的定義。

typedef  CONST  CHAR  *LPCSTR;

typedef  CONST  WCHAR *LPCWSTR;

和上面的比較,名字中就多了一個大寫的C,這個C的含義就代表是const修飾符,也就是我們上面所說 的常量指針,指向的內容不能通過這個指針被改變,但可以讀取。定義中的大寫的CONST也是一個宏,我 在第一篇文章中就講過了,代換出來也就是const, 所以請讀者自己推導一下這兩個數據類型的本質是 什麼。

所以,在windows平台下的編程過程中,凡是可以使用char* 的地方,你都可以使用LPSTR來代替, 凡是可以使用wchar_t*的地方,你都可以使用LPWSTR來代替,至於怎麼用,還是那句老話,看你個人心 情,只不過Windows的API函數中關於字符串的都是使用LP這種數據類型。但是你還是可以給他傳遞char*  或者 wchar_t* ,只要他們的本質是一樣的,那怎麼不可以呢~~

下面,我們來看一看一些示例。

char  c = 'c';  和 CHAR c = 'c';    是一樣的

wchar_t wc = L'w'; 和 WCHAR wc = L'w';    是一樣的

char* p  和 LPSTR p 是一樣的

wchar_t* wp  和 LPWSTR wp    是一樣的

再來看看動態內存分配怎麼寫的呢

char* p = new char[10]; //動態分配了十個字符

也可以寫成

CHAR* p = new CHAR[10];

LPSTR p = new CHAR[10];

LPSTR p = new char[10];

寬字節的再來一次

wchar_t* wp = new wchar_t[10];

也可以寫成下面這些形式

WCHAR*  wp = new WCHAR[10];

LPWSTR  wp = new WCHAR[10];

LPWSTR  wp = new wchar_t[10];

上面定義的這些字符指針p,wp都沒有用const修飾符,所以可以通過他們來修改他們所指向的內容。這裡留給讀者一個問題,怎麼定義有const修飾符的字符指針呢,都可以用什麼形式來寫呢,寫得越多越好喲。。

通過上面這些,我想你大概已經了解了LPSTR, LPCSTR, LPWSTR, LPCWSTR這四個數據類型了,他 們無非就是:

LPSTR  -------    char*

LPCSTR -------  const char*

LPWSTR -------  wchar_t*

LPCWSTR --------   const wchar_t* 

下面我提一個問題,如果你在你的程序中使用的字符串都是通過LPWSTR,LPCWSTR這種寬字節 (Unicode)字符指針來進行操作的,那麼在Unicode環境下編譯,完全沒有問題,如果這時你需要編譯一 套ASCII版本的程序,那你會怎麼辦呢?   你說將用LPWSTR 和LPCWSTR的地方全部換成LPSTR和 LPCSTR,再將字符串前面的L去掉就可以了,對,這是一種方法,但是!!所有人在這裡都應該知道我要 說但是,這也太麻煩了吧。難道沒有通用點的方法嗎?   有!!  所有人在這裡也都知道我會說有 ,呵呵。那就是使用微軟的通用數據類型,說通用數據類型有點太專業了,其實也就那樣,請聽我慢 慢分析來。我在上一篇文章中說過,凡是涉及字符串操作的API函數有2套,一個A系列的,一套W系列的, 還有一套宏,能根據不同的工程環境定義成不同的API函數名。那麼在字符類型上微軟也使用幾乎同樣的 技術,定義了一套宏能根據不同的工程環境定義成不同的字符數據類型。我上面就提到過的 TCHAR,LPTSTR, LPCTSTR就是這樣的類型。

首先說說TCHAR,它是被這樣定義的:

#ifdef  UNICODE

typedef  WCHAR  TCHAR;

#else

typedef  char TCHAR

看到了嗎? 它也是根據UNICODE這個宏被定義沒有,如果被定義了,那麼TCHAR代表的數據類型就是 WCHAR, 也就是wchar_t, 如果沒被定義,那麼TCHAR 就代表的是char

同樣LPTSTR,LPCTSTR也是這樣的,考慮到篇幅,我就只列出LPTSTR來給大家看看了

#ifdef   UNICODE

typedef  LPWSTR   LPTSTR;

#else

typedef  LPSTR LPTSTR;

這個是我簡化了的定義,真實面目有些復雜,不過意思也是如此,有興趣可以自己看看,在WinNT.h 這個頭文件中。下面再次解釋一下上面這個LPTSTR的定義, 還是老樣子,根據UNICODE這個宏被定義與 否來決定怎麼定義LPTSTR ,如果是定義了UNICODE這個宏,表示當前工程環境是Unicode環境,那麼 LPTSTR就被定義為了LPWSTR, LPWSTR就是我們前面所講的wchar_t* ,所以此時LPTSTR代表的數據類 型就是wchar_t* ,  如果這時的工程沒有定義UNICODE這個宏,那麼就定義LPTSTR為LPSTR,而LPSTR 就是我們前面所說的char* ,所以這是的LPTSTR就代表char*。懂了嗎?各位,我都覺得自己有些啰嗦了 ··不好意思···

然後還有一個宏需要講一下,由於我們使用通用數據類型,那麼我事先就不知道我的源代碼需要在 Unicode下編譯還是在ASCII環境下編譯,所以如下這種情況

TCHAR tc = 'a';  或者是  TCHAR tc = L'a';  是否合適呢? 前面我已經說過了字符或字符串常量前面加L代表 這是寬字節的字符或字符串,將一個寬字節字符賦值給一個TCHAR數據類型的變量tc,什麼情況下是正確 的呢?  各位思考一下呢?  

如果當前工程是Unicode環境,那麼TCHAR數據類型就是wchar_t的寬字節類型,所以tc就是寬字節字 符變量,那麼上面第二個賦值語句就是正確的,而第一個就是錯誤的。

如果反過來,當前的工程是ASCII環境,那麼TCHAR代表的是char這種數據類型,那麼第一個賦值語句 就是正確的,而第二個就是錯誤的了。

分析了這麼多,我就是要講一個宏 _T(), 只要將字符或者字符串常量放在_T()這個宏裡面,那麼 這個宏就能根據當前的環境決定是否在字符或字符串前面加L,如下面:

TCHAR tc = _T('A');

如果這麼寫,在不需要改寫源代碼的情況下,就可以編譯出Unicode和ASCII兩套程序

而只需要改變工程的環境而已。

這篇文章的內容大概就這麼多了,關於後續文章的內容安排,我會適當采納各位朋友的留言來進行安 排。

在這裡我介紹的是Windows平台下的和字符串操作有關的數據類型,至於MFC中的CString類,c++標准 庫中的string,我就不做講解了。

還有,前兩篇的文章中我說微軟定義這些數據類型為大寫是為了編碼的方便,不需要切換輸入法,很 多朋友都留言給我指出了,其實我是開了一個小玩笑,畢竟面對的是初學者,我覺得在目前這種環境下 ,沒有必要給他們講什麼代碼移植性啊,兼容性這些概念,那些在達到一定程度之後就會慢慢理解的, 所以我自己想了一個小小的優點來說明那個問題,不過還是感謝你們的補充說明,謝謝 ··

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved