1. 程式人生 > >C++字串完全指引之一 —— Win32 字元編碼

C++字串完全指引之一 —— Win32 字元編碼

原著:Michael Dunn
翻譯:Chengjie Sun



 引言

  毫無疑問,我們都看到過像 TCHAR, std::string, BSTR 等各種各樣的字串型別,還有那些以 _tcs 開頭的奇怪的巨集。你也許正在盯著顯示器發愁。本指引將總結引進各種字元型別的目的,展示一些簡單的用法,並告訴您在必要時,如何實現各種字串型別之間的轉換。
  在第一部分,我們將介紹3種字元編碼型別。瞭解各種編碼模式的工作方式是很重要的事情。即使你已經知道一個字串是一個字元陣列,你也應該閱讀本部分。一旦你瞭解了這些,你將對各種字串型別之間的關係有一個清楚地瞭解。
  在第二部分,我們將單獨講述string類,怎樣使用它及實現他們相互之間的轉換。

 字元基礎 -- ASCII, DBCS, Unicode

  所有的 string 類都是以C-style字串為基礎的。C-style 字串是字元陣列。所以我們先介紹字元型別。這裡有3種編碼模式對應3種字元型別。第一種編碼型別是單子節字符集(single-byte character set or SBCS)。在這種編碼模式下,所有的字元都只用一個位元組表示。ASCII是SBCS。一個位元組表示的0用來標誌SBCS字串的結束。
  第二種編碼模式是多位元組字符集(multi-byte character set or MBCS)。一個MBCS編碼包含一些一個位元組長的字元,而另一些字元大於一個位元組的長度。用在Windows裡的MBCS包含兩種字元型別,單位元組字元(single-byte characters)和雙位元組字元(double-byte characters)。由於Windows裡使用的多位元組字元絕大部分是兩個位元組長,所以MBCS常被用DBCS代替。
  在DBCS編碼模式中,一些特定的值被保留用來表明他們是雙位元組字元的一部分。例如,在Shift-JIS編碼中(一個常用的日文編碼模式),0x81-0x9f之間和 0xe0-oxfc之間的值表示"這是一個雙位元組字元,下一個子節是這個字元的一部分。"這樣的值被稱作"leading bytes",他們都大於0x7f。跟隨在一個leading byte子節後面的位元組被稱作"trail byte"。在DBCS中,trail byte可以是任意非0值。像SBCS一樣,DBCS字串的結束標誌也是一個單位元組表示的0。
  第三種編碼模式是Unicode。Unicode是一種所有的字元都使用兩個位元組編碼的編碼模式。Unicode字元有時也被稱作寬字元,因為它比單子節字元寬(使用了更多的儲存空間)。注意,Unicode不能被看作MBCS。MBCS的獨特之處在於它的字元使用不同長度的位元組編碼。Unicode字串使用兩個位元組表示的0作為它的結束標誌。
  單位元組字元包含拉丁文字母表,accented characters及ASCII標準和DOS作業系統定義的圖形字元。雙位元組字元被用來表示東亞及中東的語言。Unicode被用在COM及Windows NT作業系統內部。
  你一定已經很熟悉單位元組字元。當你使用char時,你處理的是單位元組字元。雙位元組字元也用char型別來進行操作(這是我們將會看到的關於雙子節字元的很多奇怪的地方之一)。Unicode字元用wchar_t來表示。Unicode字元和字串常量用字首L來表示。例如:

wchar_t wch = L''1''; // 2 bytes, 0x0031
wchar_t* wsz = L"Hello"; // 12 bytes, 6 wide characters

 字元在記憶體中是怎樣儲存的

  單位元組字串:每個字元佔一個位元組按順序依次儲存,最後以單位元組表示的0結束。例如。"Bob"的存貯形式如下:

42 6F 62 00
B o b BOS

Unicode的儲存形式,L"Bob"

42 00 6F 00 62 00 00 00
B o b BOS

使用兩個位元組表示的0來做結束標誌。

  一眼看上去,DBCS 字串很像 SBCS 字串,但是我們一會兒將看到 DBCS 字串的微妙之處,它使得使用字串操作函式和永字元指標遍歷一個字串時會產生預料之外的結果。字串" " ("nihongo")在記憶體中的儲存形式如下(LB和TB分別用來表示 leading byte 和 trail byte)

93 FA 96 7B 8C EA 00
LB TB LB TB LB TB EOS
EOS

值得注意的是,"ni"的值不能被解釋成WORD型值0xfa93,而應該看作兩個值93和fa以這種順序被作為"ni"的編碼。

 使用字串處理函式

  我們都已經見過C語言中的字串函式,strcpy(), sprintf(), atoll()等。這些字串只應該用來處理單位元組字元字串。標準庫也提供了僅適用於Unicode型別字串的函式,比如wcscpy(), swprintf(), wtol()等。
  微軟還在它的CRT(C runtime library)中增加了操作DBCS字串的版本。Str***()函式都有對應名字的DBCS版本_mbs***()。如果你料到可能會遇到DBCS字串(如果你的軟體會被安裝在使用DBCS編碼的國家,如中國,日本等,你就可能會),你應該使用_mbs***()函式,因為他們也可以處理SBCS字串。(一個DBCS字串也可能含有單位元組字元,這就是為什麼_mbs***()函式也能處理SBCS字串的原因)
  讓我們來看一個典型的字串來闡明為什麼需要不同版本的字串處理函式。我們還是使用前面的Unicode字串 L"Bob":

42 00 6F 00 62 00 00 00
B o b BOS

  因為x86CPU是little-endian,值0x0042在記憶體中的儲存形式是42 00。你能看出如果這個字串被傳給strlen()函式會出現什麼問題嗎?它將先看到第一個位元組42,然後是00,而00是字串結束的標誌,於是strlen()將會返回1。如果把"Bob"傳給wcslen(),將會得出更壞的結果。wcslen()將會先看到0x6f42,然後是0x0062,然後一直讀到你的緩衝區的末尾,直到發現00 00結束標誌或者引起了GPF。
  到目前為止,我們已經討論了str***()和wcs***()的用法及它們之間的區別。Str***()和_mbs**()之間的有區別區別呢?明白他們之間的區別,對於採用正確的方法來遍歷DBCS字串是很重要的。下面,我們將先介紹字串的遍歷,然後回到str***()與_mbs***()之間的區別這個問題上來。

 正確的遍歷和索引字串

  因為我們中大多數人都是用著SBCS字串成長的,所以我們在遍歷字串時,常常使用指標的++-和-操作。我們也使用陣列下標的表示形式來操作字串中的字元。這兩種方式是用於SBCS和Unicode字串,因為它們中的字元有著相同的寬度,編譯器能正確的返回我們需要的字元。
  然而,當碰到DBCS字串時,我們必須拋棄這些習慣。這裡有使用指標遍歷DBCS字串時的兩條規則。違背了這兩條規則,你的程式就會存在DBCS有關的bugs。

  • 1.在前向遍歷時,不要使用++操作,除非你每次都檢查lead byte;
  • 2.永遠不要使用-操作進行後向遍歷。
  •   我們先來闡述規則2,因為找到一個違背它的真實的例項程式碼是很容易的。假設你有一個程式在你自己的目錄裡儲存了一個設定檔案,你把安裝目錄儲存在登錄檔中。在執行時,你從登錄檔中讀取安裝目錄,然後合成配置檔名,接著讀取該檔案。假設,你的安裝目錄是C:\Program Files\MyCoolApp,那麼你合成的檔名應該是C:\Program Files\MyCoolApp\config.bin。當你進行測試時,你發現程式執行正常。
      現在,想象你合成檔名的程式碼可能是這樣的:

    bool GetConfigFileName ( char* pszName, size_t nBuffSize )
    {
        char szConfigFilename[MAX_PATH];
     
        // Read install dir from registry... we''ll assume it succeeds.
     
        // Add on a backslash if it wasn''t present in the registry value.
        // First, get a pointer to the terminating zero.
        char* pLastChar = strchr ( szConfigFilename, ''\0'' );
     
        // Now move it back one character.
        pLastChar--;  
     
        if ( *pLastChar != ''\\'' )
            strcat ( szConfigFilename, "\\" );
     
        // Add on the name of the config file.
        strcat ( szConfigFilename, "config.bin" );
     
        // If the caller''s buffer is big enough, return the filename.
        if ( strlen ( szConfigFilename ) >= nBuffSize )
            return false;
        else
            {
            strcpy ( pszName, szConfigFilename );
            return true;
            }
    } 
      這是一段很健壯的程式碼,然而在遇到 DBCS 字元時它將會出錯。讓我們來看看為什麼。假設一個日本使用者使用了你的程式,把它安裝在 C:\。下面是這個名字在記憶體中的儲存形式:
     
    43 3A 5C 83 88 83 45 83 52 83 5C 00
    LB TB LB TB LB TB LB TB
    C : \ EOS

      當使用 GetConfigFileName() 檢查尾部的''\\''時,它尋找安裝目錄名中最後的非0位元組,看它是等於''\\''的,所以沒有重新增加一個''\\''。結果是程式碼返回了錯誤的檔名。
      哪裡出錯了呢?看看上面兩個被用藍色高量顯示的位元組。斜槓''\\''的值是0x5c。'' ''的值是83 5c。上面的程式碼錯誤的讀取了一個 trail byte,把它當作了一個字元。
      正確的後向遍歷方法是使用能夠識別DBCS字元的函式,使指標移動正確的位元組數。下面是正確的程式碼。(指標移動的地方用紅色標明)

    bool FixedGetConfigFileName ( char* pszName, size_t nBuffSize )
    {
        char szConfigFilename[MAX_PATH];
     
        // Read install dir from registry... we''ll assume it succeeds.
     
        // Add on a backslash if it wasn''t present in the registry value.
        // First, get a pointer to the terminating zero.
        char* pLastChar = _mbschr ( szConfigFilename, ''\0'' );
     
        // Now move it back one double-byte character.
        pLastChar = CharPrev ( szConfigFilename, pLastChar );
     
        if ( *pLastChar != ''\\'' )
            _mbscat ( szConfigFilename, "\\" );
     
        // Add on the name of the config file.
        _mbscat ( szConfigFilename, "config.bin" );
    
         // If the caller''s buffer is big enough, return the filename.
        if ( _mbslen ( szInstallDir ) >= nBuffSize )
            return false;
        else
            {
            _mbscpy ( pszName, szConfigFilename );
            return true;
            }
    }
      上面的函式使用CharPrev() API使pLastChar向後移動一個字元,這個字元可能是兩個位元組長。在這個版本里,if條件正常工作,因為lead byte永遠不會等於0x5c。
      讓我們來想象一個違背規則1的場合。例如,你可能要檢測一個使用者輸入的檔名是否多次出現了'':''。如果,你使用++操作來遍歷字串,而不是使用CharNext(),你可能會發出不正確的錯誤警告如果恰巧有一個trail byte它的值的等於'':''的值。
    與規則2相關的關於字串索引的規則:
    2a. 永遠不要使用減法去得到一個字串的索引。

    違背這條規則的程式碼和違背規則2的程式碼很相似。例如,

    char* pLastChar = &szConfigFilename [strlen(szConfigFilename) - 1];

    這和向後移動一個指標是同樣的效果。

     回到關於str***()和_mbs***()的區別

      現在,我們應該很清楚為什麼_mbs***()函式是必需的。Str***()函式根本不考慮DBCS字元,而_mbs***()考慮。如果,你呼叫strrchr("C:\\ ", ''\\''),返回結果可能是錯誤的,然而_mbsrchr()將會認出最後的雙位元組字元,返回一個指向真的''\\''的指標。
      關於字串函式的最後一點:str***()和_mbs***()函式認為字串的長度都是以char來計算的。所以,如果一個字串包含3個雙位元組字元,_mbslen()將會返回6。Unicode函式返回的長度是按wchar_t來計算的。例如,wcslen(L"Bob")返回3。

     Win32 API中的MBCS和Unicode

    兩組 APIs: 
      儘管你也許從來沒有注意過,Win32中的每個與字串相關的API和message都有兩個版本。一個版本接受MBCS字串,另一個接受Unicode字串。例如,根本沒有SetWindowText()這個API,相反,有SetWindowTextA()和SetWindowTextW()。字尾A表明這是MBCS函式,字尾W表示這是Unicode版本的函式。
      當你 build 一個 Windows 程式,你可以選擇是用 MBCS 或者 Unicode APIs。如果,你曾經用過VC嚮導並且沒有改過預處理的設定,那表明你用的是MBCS版本。那麼,既然沒有 SetWindowText() API,我們為什麼可以使用它呢?winuser.h標頭檔案包含了一些巨集,例如:

    BOOL WINAPI SetWindowTextA ( HWND hWnd, LPCSTR lpString );
    BOOL WINAPI SetWindowTextW ( HWND hWnd, LPCWSTR lpString );
     
    #ifdef UNICODE
    #define SetWindowText  SetWindowTextW
    #else
    #define SetWindowText  SetWindowTextA
    #endif 
    當使用MBCS APIs來build程式時,UNICODE沒有被定義,所以前處理器看到:
    #define SetWindowText SetWindowTextA

      這個巨集定義把所有對SetWindowText的呼叫都轉換成真正的API函式SetWindowTextA。(當然,你可以直接呼叫SetWindowTextA() 或者 SetWindowTextW(),雖然你不必那麼做。)
      所以,如果你想把預設使用的API函式變成Unicode版的,你可以在前處理器設定中,把_MBCS從預定義的巨集列表中刪除,然後新增UNICODE和_UNICODE。(你需要兩個都定義,因為不同的標頭檔案可能使用不同的巨集。) 然而,如果你用char來定義你的字串,你將會陷入一個尷尬的境地。考慮下面的程式碼:

    HWND hwnd = GetSomeWindowHandle();
    char szNewText[] = "we love Bob!";
    SetWindowText ( hwnd, szNewText );

    在前處理器把SetWindowText用SetWindowTextW來替換後,程式碼變成:

    HWND hwnd = GetSomeWindowHandle();
    char szNewText[] = "we love Bob!";
    SetWindowTextW ( hwnd, szNewText );

      看到問題了嗎?我們把單位元組字串傳給了一個以Unicode字串做引數的函式。解決這個問題的第一個方案是使用 #ifdef 來包含字串變數的定義:

    HWND hwnd = GetSomeWindowHandle();
    #ifdef UNICODE
    wchar_t szNewText[] = L"we love Bob!";
    #else
    char szNewText[] = "we love Bob!";
    #endif
    SetWindowText ( hwnd, szNewText );

    你可能已經感受到了這樣做將會使你多麼的頭疼。完美的解決方案是使用TCHAR.

     使用TCHAR

      TCHAR是一種字串型別,它讓你在以MBCS和UNNICODE來build程式時可以使用同樣的程式碼,不需要使用繁瑣的巨集定義來包含你的程式碼。TCHAR的定義如下:

    #ifdef UNICODE
    typedef wchar_t TCHAR;
    #else
    typedef char TCHAR;
    #endif

    所以用MBCS來build時,TCHAR是char,使用UNICODE時,TCHAR是wchar_t。還有一個巨集來處理定義Unicode字串常量時所需的L字首。

    #ifdef UNICODE
    #define _T(x) L##x
    #else
    #define _T(x) x
    #endif

      ##是一個預處理操作符,它可以把兩個引數連在一起。如果你的程式碼中需要字串常量,在它前面加上_T巨集。如果你使用Unicode來build,它會在字串常量前加上L字首。

    TCHAR szNewText[] = _T("we love Bob!");

      像是用巨集來隱藏SetWindowTextA/W的細節一樣,還有很多可以供你使用的巨集來實現str***()和_mbs***()等字串函式。例如,你可以使用_tcsrchr巨集來替換strrchr()、_mbsrchr()和wcsrchr()。_tcsrchr根據你預定義的巨集是_MBCS還是UNICODE來擴充套件成正確的函式,就像SetWindowText所作的一樣。
      不僅str***()函式有TCHAR巨集。其他的函式如, _stprintf(代替sprinft()和swprintf()),_tfopen(代替fopen()和_wfopen())。 MSDN中"Generic-Text Routine Mappings."標題下有完整的巨集列表。

     字串和TCHAR typedefs

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

    type Meaning in MBCS builds Meaning in Unicode builds
    WCHAR wchar_t wchar_t
    LPSTR zero-terminated string of char (char*) zero-terminated string of char (char*)
    LPCSTR constant zero-terminated string of char (const char*) constant zero-terminated string of char (const char*)
    LPWSTR zero-terminated Unicode string (wchar_t*) zero-terminated Unicode string (wchar_t*)
    LPCWSTR constant zero-terminated Unicode string (const wchar_t*) constant zero-terminated Unicode string (const wchar_t*)
    TCHAR char wchar_t
    LPTSTR zero-terminated string of TCHAR (TCHAR*) zero-terminated string of TCHAR (TCHAR*)
    LPCTSTR constant zero-terminated string of TCHAR (const TCHAR*) constant zero-terminated string of TCHAR (const TCHAR*)

     何時使用 TCHAR 和 Unicode

      到現在,你可能會問,我們為什麼要使用Unicode。我已經用了很多年的char。下列3種情況下,使用Unicode將會使你受益:

  • 1.你的程式只執行在Windows NT系統中。
  • 2. 你的程式需要處理超過MAX_PATH個字元長的檔名。
  • 3. 你的程式需要使用XP中引入的只有Unicode版本的API.
  •   Windows 9x 中大多數的 API 沒有實現 Unicode 版本。所以,如果你的程式要在windows 9x中執行,你必須使用MBCS APIs。然而,由於NT系統內部都使用Unicode,所以使用Unicode APIs將會加快你的程式的執行速度。每次,你傳遞一個字串呼叫MBCS API,作業系統會把這個字串轉換成Unicode字串,然後呼叫對應的Unicode API。如果一個字串被返回,作業系統還要把它轉變回去。儘管這個轉換過程被高度優化了,但它對速度造成的損失是無法避免的。
      只要你使用Unicode API,NT系統允許使用非常長的檔名(突破了MAX_PATH的限制,MAX_PATH=260)。使用Unicode API的另一個優點是你的程式會自動處理使用者輸入的各種語言。所以一個使用者可以輸入英文,中文或者日文,而你不需要額外編寫程式碼去處理它們。
      最後,隨著windows 9x產品的淡出,微軟似乎正在拋棄MBCS APIs。例如,包含兩個字串引數的SetWindowTheme() API只有Unicode版本的。使用Unicode來build你的程式將會簡化字串的處理,你不必在MBCS和Unicdoe之間相互轉換。
      即使你現在不使用Unicode來build你的程式,你也應該使用TCHAR及其相關的巨集。這樣做不僅可以的程式碼可以很好地處理DBCS,而且如果將來你想用Unicode來build你的程式,你只需要改變一下前處理器中的設定就可以實現了。

     作者簡介
      Michael Dunn:居住在陽光城市洛杉磯。他是如此的喜歡這裡的天氣以致於想一生都住在這裡。他在4年級時開始程式設計,那時用的電腦是Apple //e。1995年,在 UCLA 獲得數學學士學位,隨後在Symantec 公司做 QA 工程師,在 Norton AntiVirus 組工作。他自學了 Windows 和 MFC 程式設計。1999-2000年,他設計並實現了 Norton AntiVirus 的新介面。 
      Michael 現在在 Napster(一個提供線上訂閱音樂服務的公司)做開發工作,他還開發了UltraBar,一個IE工具欄外掛,它可以使網路搜尋更加容易,給了 googlebar 以沉重打擊;他還開發了 CodeProject SearchBar;與人共同建立了 Zabersoft 公司,該公司在洛杉磯和丹麥的 Odense 都設有辦事處。
      他喜歡玩遊戲。愛玩的遊戲有 pinball, bike riding,偶爾還玩 PS, Dreamcasth 和 MAME 遊戲。他因忘了自己曾經學過的語言:法語、漢語、日語而感到悲哀。

    相關推薦

    C++字串完全指引之一 —— Win32 字元編碼

    原著:Michael Dunn 翻譯:Chengjie Sun  引言   毫無疑問,我們都看到過像 TCHAR, std::string, BSTR 等各種各樣的字串型別,還有那些以 _tcs 開頭的奇怪的巨集。你也許正在盯著顯示器發愁。本指引將總結引進各種字元

    【miscellaneous】【C/C++語言】UTF8與GBK字元編碼之間的相互轉換

    1 class CChineseCode 2 3 { 4 5 public: 6 7 static void UTF_8ToUnicode(wchar_t* pOut,char *pText); // 把UTF-8轉換成Unicode

    C++字串完全指南

    1、什麼是const? 常型別是指使用型別修飾符const說明的型別,常型別的變數或物件的值是不能被更新 的。(當然,我們可以偷樑換柱進行更新:) 2、為什麼引入const? const 推出的初始目的,正是為了取代預編譯指令,消除它的缺點,同時繼承它的優點 。 3、cons有什麼主要的作用

    C++字串剔除首尾不可見字元

    void Trim(string &str) { TrimLeft(str); TrimRight(str); } void TrimLeft(string &str) { if (str.empty()) { return; } st

    詳解C語言在字串的指定位置插入字元

    問題分析 在字串S的所有數字字元前加一個$字元,可以有兩種實現方法。方法一:用串S拷貝出另一個串T,對串T從頭至尾掃描,對非數字字元原樣寫入串S,對於數字字元先寫一個$符號再寫該數字字元,最後,在S串尾加結束標誌。使用此方法是犧牲空間,贏得時間。方法二:對串S從頭至尾掃描,當遇到數字字元時,從該字元至串

    字串字元編碼

    由於計算機是美國人發明的,因此,最早只有127個字元被編碼到計算機裡,也就是大小寫英文字母、數字和一些符號,這個編碼表被稱為ASCII編碼,比如大寫字母A的編碼是65,小寫字母z的編碼是122。 但是要處理中文顯然一個位元組是不夠的,至少需要兩個位元組,而且還不能和ASCII編碼衝突,所以,

    C# 字串中特定字元判斷

    /// <summary> /// 計算字串中子串出現的次數 /// </summary> /// <param name="str">字串</param> /// <param nam

    C#實戰015:Excel操作-字元編碼轉換

         在讀取Excel時遇到一個問題,那就是讀取出來的單表出現了亂碼的現象,我們可以看到很多漢字無法識別出來。          在存入時對字元編碼進行指定: public void getHeader

    利用字元編碼集對中文長度的不同來判斷字串中有沒有中文

    是這樣的,在日常開發中遇到一個問題:判斷一個字串中是否含有中文。本來是很簡單的一個需求,用正則就搞定了。然而這是一個很老舊的一個系統,有自己的一套開發語言。偏偏不支援正則,這就難住我了。 當時想到一個笨辦法:把三千個常用漢字寫在一個配置檔案中,把要判斷的字串分割為一個個字元,一個個的去配置檔案中找,看能不能

    C語言找出字串中的特定的字元,並輸出

    這裡我們用到了函式 strchr 這個函式返回值是一個指標 函式引數是 一個字串和一個字元。 #include <stdio.h> #include<string.h> void main() { char str[80]; char c

    [Swift]字串根據索引獲取指定字元,依據ASCII編碼實現字元和整數的快速轉換

    ASCII(American Standard Code for Information Interchange,美國資訊交換標準程式碼)是基於拉丁字母的一套電腦編碼系統,主要用於顯示現代英語和其他西歐語言。 它是現今最通用的單位元組編碼系統,並等同於國際標準ISO/IEC 646。

    C語言實現一個函式,可以左旋字串中的k個字元

    // 實現一個函式,可以左旋字串中的k個字元   例如:                 //ABCD左旋一個字元得到BCDA                 //ABCD左旋兩個字元得到CDAB    解題思路:                   1> 先理思

    C++的三種字元編碼方式

    WCHAR wchar_t wchar_t LPSTR zero-terminated string of char (char*) zero-terminated string of char (char*) LPCSTR constant zero-terminated string of char (c

    中文亂碼解決之一 JS的編碼、解碼及C#中對應的解碼、編碼

    JS的編碼、解碼及C#中對應的解碼、編碼 1、escape 定義和用法 escape對字串資料編碼,如果是對url進行編碼必須用encodeURI或是encodeURLComponent,解碼使用:unescape。 返回值 字符集是unicode,編碼成16進位制。 說明

    ACMNO.40 C語言-子串 有一字串,包含n個字元。寫一函式,將此字串中從第m個字元開始的全部字元複製成為另一個字串

    題目描述 有一字串,包含n個字元。 寫一函式,將此字串中從第m個字元開始的全部字元複製成為另一個字串。 輸入 數字n 一行字串 數字m 輸出 從m開始的子串 樣例輸入 6 abcdef 3 樣例輸出 cdef 來源/分類 C語言

    .NET(C#):字元編碼(Encoding)和位元組順序標記(BOM)

    什麼是字元順序標記(BOM) 計算機內部資料儲存都是二進位制的,只有知道一段資料的二進位制儲存格式,這段資料才有意義。所謂的文字檔案其實就是用一種特定的字元編碼來將二進位制源資料轉換成文字。多數文字編輯器都可以編輯不同編碼的文字檔案,那麼文字編輯器是怎樣通過源二

    C語言中,為什麼字串可以賦值給字元指標變數

    1.以字串形式出現的,編譯器都會為該字串自動新增一個0作為結束符,如在程式碼中寫  "abc",那麼編譯器幫你儲存的是"abc\0" 2."abc"是常量嗎?答案是有時是,有時不是。 不是常量的情況:"abc"作為字元陣列初始值的時候就不是,如                  char str[] = "

    C++中數字與字串之間的轉換(包括C++11新標準和寬窄字元轉換)

    1、字串數字之間的轉換 (1)string --> char *    string str("OK");    char * p = str.c_str(); (2)char * -->string    char *p = "OK";    string str(p); (3)char *

    C++字串字元的分割與轉換

    今日一些小見解。 //未初始化錯誤 string a; a[0]='1'; //未初始化錯誤 string *q; q[0]="a"; 想單獨為未初始化的string逐個增加元素: string str; str.push

    Python判斷字串、檔案字元編碼

    本段工具程式碼用於判斷字串或者文字檔案的字元編碼型別,可以識別常用的UTF-8,UTF-8-SIG,UTF-16,GBK,GB2312 ,GB18030 ,ASCII字元編碼格式,如果有特殊字符集需求,可以擴充字元編碼列表。 程式碼如下: [charse