[C] wchar_t的格式控制字元(VC、BCB、GCC、C99標準)

來源:互聯網
上載者:User

作者:zyl910

  隨著wchar_t類型引入C語言,字串處理變得越來越複雜。例如字串輸出有printf、wprintf這兩個函數,當參數中既有char字串又有wchar_t字串時,該怎麼填寫格式控制字元呢?本文對此進行探討。

一、翻閱文檔

  先翻閱一下各個編譯器的文檔及C99標準,看看它們對格式控制字元的說明。

1.1 VC的文檔

  在MSDN官網上,可以找到printf與wprintf的格式字串的說明,在《Format Specification Fields: printf and wprintf Functions》(http://msdn.microsoft.com/en-us/library/56e442dc(v=vs.110).aspx)。摘錄——
A format specification, which consists of optional and required fields, has the following form:
% [flags] [width] [.precision] [{h | l | ll | I | I32 | I64}]type

  先點“type”查看類型,進入《printf Type Field Characters》頁面(http://msdn.microsoft.com/en-us/library/hf4y5e3w(v=vs.110).aspx)。摘錄——
printf Type Field Characters

Character Type Output format
c int or wint_t When used with printf functions, specifies a single-byte character; when used with wprintf functions, specifies a wide character.
C int or wint_t When used with printf functions, specifies a wide character; when used with wprintf functions, specifies a single-byte character.
s String When used with printf functions, specifies a single-byte–character string; when used with wprintf functions, specifies a wide-character string. Characters are displayed up to the first null character or until the precision value is reached.
S String When used with printf functions, specifies a wide-character string; when used with wprintf functions, specifies a single-byte–character string. Characters are displayed up to the first null character or until the precision value is reached.

 

  後退,再點擊《Size Specification》(http://msdn.microsoft.com/en-us/library/tcxf1dw6(v=vs.110).aspx)的連結。摘錄——

To specify Use prefix With type specifier
Single-byte character with printf functions h c or C
Single-byte character with wprintf functions h c or C
Wide character with printf functions l c or C
Wide character with wprintf functions l c or C
Single-byte – character string with printf functions h s or S
Single-byte – character string with wprintf functions h s or S
Wide-character string with printf functions l s or S
Wide-character string with wprintf functions l s or S
Wide character w c
Wide-character string w s

 

 

Thus to print single-byte or wide-characters with printf functions and wprintf functions, use format specifiers as follows.

To print character as Use function With format specifier
single byte printf c, hc, or hC
single byte wprintf C, hc, or hC
wide wprintf c, lc, lC, or wc
wide printf C, lc, lC, or wc

 

To print strings with printf functions and wprintf functions, use the prefixes h and l analogously with format type-specifiers s and S.

  上面介紹了很多控制字元。整理一下,發現對字串來說,最有用的是這三個——
hs:printf、wprintf均是char字串。
ls:printf、wprintf均是wchar_t字串。
s:printf是char字串,而wprintf是wchar_t字串。與TCHAR搭配使用很方便。

1.2 BCB的文檔

  開啟BCB6協助檔案中的“C Runtime Library Reference”,在索引中輸入“printf”,能很快找到格式控制字元的說明——

  觀察後可發現,它與VC是相容的。可以使用hs/ls/s分別處理char/wchar_t/TCHAR字串。

1.3 GCC的文檔

  我這裡裝了Fedora 17,並裝好了GCC 4.7.0。
  開啟控制台,輸入“man 3 wprintf”查看wprintf函數的文檔。摘錄——
c
If no l modifier is present, the int argument is converted to a wide character by a call to the btowc(3) function, and the resulting wide character is written. If an l modifier is present, the wint_t (wide character) argument is written.

s
If no l modifier is present: The const char * argument is expected to be a pointer to an array of character type (pointer to a string) containing a multibyte character sequence beginning in the initial shift state. Characters from the array are converted to wide characters (each by a call to the mbrtowc(3) function with a conversion state starting in the initial state before the first byte). The resulting wide characters are written up to (but not including) the terminating null wide character. If a precision is specified, no more wide characters than the number specified are written. Note that the precision determines the number of wide characters written, not the number of bytes or screen positions. The array must contain a terminating null byte, unless a precision is given and it is so small that the number of converted wide characters reaches it before the end of the array is reached.
If an l modifier is present: The const wchar_t * argument is expected to be a pointer to an array of wide characters. Wide characters from the array are written up to (but not including) a terminating null wide character. If a precision is specified, no more than the number specified are written. The array must contain a terminating null wide character, unless a precision is given and it is smaller than or equal to the number of wide characters in the array.

  根據上面的描述,GCC似乎只支援這兩種字串的格式控制字元——
s:printf、wprintf均是char字串。
ls:printf、wprintf均是wchar_t字串。

1.4 C99標準

  在C99標準的“7.24.2.1 The fwprintf function”中介紹了fwprintf等寬字元函數的格式控制字元。摘錄——
7 The length modifiers and their meanings are:

h
Specifies that a following d, i, o, u, x, or X conversion specifier applies to a short int or unsigned short int argument (the argument will have been promoted according to the integer promotions, but its value shall be converted to short int or unsigned short int before printing); or that a following n conversion specifier applies to a pointer to a short int argument.

l (ell)
Specifies that a following d, i, o, u, x, or X conversion specifier applies to a long int or unsigned long int argument; that a following n conversion specifier applies to a pointer to a long int argument; that a following c conversion specifier applies to a wint_t argument; that a following s conversion specifier applies to a pointer to a wchar_t argument; or has no effect on a following a, A, e, E, f, F, g, or G conversion specifier.

……

8 The conversion specifiers and their meanings are:

c
If no l length modifier is present, the int argument is converted to a wide character as if by calling btowc and the resulting wide character is written.
If an l length modifier is present, the wint_t argument is converted to wchar_t and written.

s
If no l length modifier is present, the argument shall be a pointer to the initial element of a character array containing a multibyte character sequence beginning in the initial shift state. Characters from the array are converted as if by repeated calls to the mbrtowc function, with the conversion state described by an mbstate_t object initialized to zero before the first multibyte character is converted, and written up to (but not including) the terminating null wide character. If the precision is specified, no more than that many wide characters are written. If the precision is not specified or is greater than the size of the converted array, the converted array shall contain a null wide character.
If an l length modifier is present, the argument shall be a pointer to the initial element of an array of wchar_t type. Wide characters from the array are written up to (but not including) a terminating null wide character. If the precision is specified, no more than that many wide characters are written. If the precision is not specified or is greater than the size of the array, the array shall contain a null wide character.

  可見,C99標準中c、s僅有“l”長度修正,沒“l”的是char字串,有“l”的是wchar_t字串。

1.5 小結

  根據上面的資料,可以整理出一份表格——

  VC和BCB GCC和C99標準
printf wprintf printf wprintf
s char wchar_t char char
S wchar_t char * *
hs char char * *
ls wchar_t wchar_t wchar_t wchar_t

*:未定義。

二、測試程式

  參考了上述文檔,我覺的應該編寫一個測試程式,實際測一下各個編譯器對wchar_t格式控制字元的支援性。
  測試程式的代碼如下——

#include <stdio.h>#include <locale.h>#include <string.h>#include <wchar.h>char* psa = "CHAR";    // 單位元組字串.wchar_t* psw = L"WCHAR";    // 寬字元串.wchar_t* pst = L"TCHAR";    // 類型與printf/wprintf匹配的字串.int main(){    setlocale(LC_ALL, "");    // 使用系統當前字碼頁.        // test    wprintf(L"A:\t%hs\n", psa);    wprintf(L"W:\t%ls\n", psw);    wprintf(L"T:\t%s\n", pst);        return 0;}

 

  如果運行正常的話,該程式的輸出結果應該是——
A: CHAR
W: WCHAR
T: TCHAR

三、測試結果3.1 VC6與BCB6測試

  跟意料中的一樣,VC6與BCB6均正確輸出了——
A: CHAR
W: WCHAR
T: TCHAR

3.2 fedora中的GCC測試

  Fedora 17,GCC 4.7.0——

  第3項的輸出結果有誤是很容易理解的。因為GCC文檔與C99標準都規定“無l時的s代表char字串”,而pst實際上是一個wchar_t字串。
  而第1項正確的輸出結果反倒有點迷惑——GCC文檔和C99標準中s不是沒有“h”長度修正嗎。想了一下才明白,文檔上說的是“無l時的s代表char字串”,因“hs”沒有“l”,所以被識別為char字串也是符合標準。

3.3 mingw中的GCC測試

  MinGW(20120426),GCC 4.6.2——

  MinGW雖然用的也是GCC編譯器,但為了相容Windows環境,它調整了格式控制字元規則,與VC保持一致。

四、總結

  根據上面的測試結果,修訂前面的表格——

  VC、BCB、MinGW Linux下的GCC、C99標準
printf wprintf printf wprintf
s char wchar_t char char
S wchar_t char * *
hs char char char char
ls wchar_t wchar_t wchar_t wchar_t

  總結如下——
1) 需要輸出char字串時,使用“hs”。
2) 需要輸出wchar_t字串時,使用“ls”。
3) 需要輸出TCHAR字串時,使用“s”,僅對VC、BCB、MinGW等Windows平台的編譯器有效。

 

參考文獻——
《ISO/IEC 9899:1999 (C99)》。ISO/IEC,1999。www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf
《C99標準》。yourtommy。http://blog.csdn.net/yourtommy/article/details/7495033
《[VS2012] Format Specification Fields: printf and wprintf Functions》。http://msdn.microsoft.com/en-us/library/56e442dc(v=vs.110).aspx
《[VS2012] printf Type Field Characters》。http://msdn.microsoft.com/en-us/library/hf4y5e3w(v=vs.110).aspx
《[VS2012] Size Specification》。http://msdn.microsoft.com/en-us/library/tcxf1dw6(v=vs.110).aspx
《wprintf(3) - Linux manual page》。http://www.kernel.org/doc/man-pages/online/pages/man3/wprintf.3.html

 

源碼下載——
http://files.cnblogs.com/zyl910/wcharfmt.rar

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.