您好,登錄后才能下訂單哦!
前幾日在看一個關于多線程下locale問題:在多線程下locale not independent問題。無意中在網上搜到一篇講解C locale 和C++ locale的文章,覺得很好,鏈接如下:
http://stdcxx.apache.org/doc/stdlibug/24-3.html
今天嘗試翻譯一下,加深理解。翻譯如下:
Apache C++ 標準庫用戶向導
24.3 C Locale和C++ Locales區別
正如我們目前所看到的,C Locale和C++ Locales提供了類似服務。然而,C++ Locale所想表達的語義信息卻不同于C Locale。
為了進一步細節地探索他們的不同,我們來看看locales是如何被使用的。
24.3.1 C locale的一般使用
c locale 通常會被用作默認locale (defaule locale),本地locale (native locale),或者是多locale應用(multiple locale applications)中。
Default locale:作為開發,如果你從不涉及到互聯網功能的開發需求,那么你也不會調用std::setlocale()。如果你認為你用戶總是在標準的US English ASCII下使用你的應用,那么你也沒有localization的需求。如果你連locale都不知道的話,那么你一定總是在默認的locale下,也就是在US English ASCII locale下開發你的應用。
Native locale:如果你確實有計劃在你的程序里支持本地化,最合適的策略就是在程序一開始就獲取本地local信息,然后不要再更改設置。這樣你的應用會適配的選擇某個特定locale,并貫穿到應用的整個運行過程中。如此用戶在啟動應用之前就可以顯示的設置他們喜歡的locale。在UNIX系統中,他們通過設置環境變量,例如LANG來設置locale;其它操作系統有其它的方法去設置locale。
你在程序里可以通過調用set::setlocale("")以及傳一個空字符串作為locale的名字來指定一個用戶有偏好的locale設置。空的字符串是告訴setlocale去使用用戶在環境中指定的locale作為應用的默認locale。
Multiple locales:有時候你不得不工作在多locales的情形下。例如,一個應用是給瑞士人使用的,那么你期望輸出的消息能支持意大利語,法語和德語。因為C locale是一個全局的(global)的數據結構,所以你必須在不同locales之間多次切換去支持不同語言。
我們來看一個在多locales情形下工作的例子。想象一下你的應用需要打印費用清單給全世界的顧客。那個費用清單一定是符合顧客本地語言的,所以你的應用就必須根據不同的語言打印不同語言費用清單。其中費用清單里的價格是一個獨立的價格列表。假設我們的應用被一個美國公司使用,價格列表是US English。
應用在US English下讀價格列表(輸入),但是寫費用清單(輸出)是支持客戶本地語言的,比如說德語。因為C有僅有一個全局的(global) locale,全局的locale會同時影響輸入和輸出,所以全局的locale需要在輸入和輸出之間進行切換。在價格從英文價格列表中讀出來之前,locale必須先從德文locale切換成US English locale。在價格加入到費用清單之前,全局的locale必須再切換成德文locale。為了從價格列表里讀下一個價格,locale又要切換為English,如此反復。 圖6解釋了這個過程。
Figure 6 : Multiple locales in C
這是剛才例子的C代碼:
double price;
char buf[SZ];
while ( ... ) // processing the German invoice
{
std::setlocale(LC_ALL, "En_US");
std::fscanf(priceFile, "%lf", &price);
// convert $ to DM according to the current exchange rate
std::setlocale(LC_ALL, "De_DE");
std::strfmon(buf,SZ, "%n", price);
std::fprintf(invoiceFile, "%s", buf);
}
使用C++ locale對象可以極具地簡化這個過程。The iostreams in the C++ Standard Library are internationalized so that streams can be imbued with separate locale objects. C++標準庫下的iostreams是國際通用的(internationalized),所以streams能夠貫穿獨立的locale對象。例如,輸入流是English locale對象,輸出流是German locale對象。如此,locales切換就沒有必要了,正如圖7所顯示的:
Figure 7: Multiple locales in C++
這是C++代碼的例子:
priceFile.imbue(std::locale("En_US"));
invoiceFile.imbue(std::locale("De_DE"));
moneytype price;
while ( ... ) // processing the German invoice
{
priceFile >> price;
// convert $ to DM according to the current exchange rate
invoiceFile << price;
}
假設這個例子已經有
貨幣值的例子相對簡單,在locales之間切換不是很麻煩。然而,一旦涉及到代碼層面切換,這個問題就變的主要起來了。
為了更好的理解這一點,讓我們再看一下圖2中的JIS encoding scheme使用shift語法如何在圖8中變大方便起來的。正如你說記得那樣,當你解析字符句子的時候,你必須要維護一個shift狀態。
Figure 8: Figure 2中日文文本在JIS中的編碼
假設你在解析一個含有在JIS下編碼的文本的多字節文件,正如你在圖9中所看到的。當你解析這個文件,你不得不跟蹤shift狀態以至于你可以知道如何翻譯你所讀到的字符節,如何以合適的寬字節來表達這些字符節。
Figure 9:使用全局C locale解析多字節文本輸入
在解析文本過程中,全局C locale可以來回切換;例如,文本輸入的locale狀態從JIS 編碼切換到EUC編碼。每當locale切換到新的狀態,當前的locale狀態就無效了,在你的應用里你不得不小心維護由locale切換帶來的狀態切換。
當local切換變得通用的時候,這個問題就迎刃而解了。然而,在多線程環境下,全局C locale會帶來嚴重的問題,因為一個線程下的locale狀態不經意間會被另外一個線程下的locale給更改了。因為這個原因,在多線程環境下通用化C程序就很困難。
如果你使用C++ locales,另一方面這個問題也很容易解決了。你可以每個數據流綁定到一個獨立的locale對象,這樣問題就不會出現locale被不期望修改的問題。讓我們來看一個C++ locales的例子。
priceFile.imbue(std::locale("En_US"));
invoiceFile.imbue(std::locale("De_DE"));
moneytype price;
while ( ... ) // processing the German invoice
{
priceFile >> price;
// convert $ to DM according to the current exchange rate
invoiceFile << price;
}
24.3.2 C++ locales的一般使用
C++ locale通常被用作支持多locales的默認的locale;和全局locale。
Classic locale. 如果你涉及的程序并不需要支持本地化工作,那么使用C++ locales和使用C locales沒什么區別。 如果你總是認為你的應用程序的用戶總是在US English ASCII環境下,那么你也不需要請求本地化。對于你,C++標準庫提供了一個預定義的locale對象std::locale::classic(),它正是US English ASCII locale。
Native locale. Native locale是受用戶和系統管理員喜歡的一個locale。在UNIX系統里,通常通過設置環境變量例如LANG來完成。你也可以通過調用構造函數std::locale("")為native locale創建一個C++ locale對象,也就是通過請求一個以空字符串作為輸入創建的locale。這個空字符串告訴系統從環境中得到locale的名字,這等同于C庫函數的std::setlocale("")。
Named locales. 正如上面所說,一個local可以有一個名字。標準的locale的名字是“c”。不幸的是,其他locales的名字平臺依賴。查詢你的系統文檔來獲知你的系統是什么locales被安裝以及locale是如何命名的。如果你嘗試用一個無效的名字去創建一個locale對象,構造函數會拋出一個runtime_error異常。
Multiple locales. 當你使用C++ locales,工作在不同的locales就變得很容易了。你在C下面所做的locales切換,在C++里就不再有必要了。你可以綁定每個流到不同的locale 對象。你也可以傳遞locales對象到不同地方使用,這完全沒有問題。
Global locale. 正如C,C++也有全局的locale。 一開始,全局locale是如前所說的標準locale。你也可以通過調用std::locale::global()去改變全局locale。
你也可以通過調用默認的構造函數std::locale::locale(),為當前的全局locale創建一個快照。這些快照也是locales object獨立的,不受接下來的全局locale改變的影響。
通用化組件像iostreams,使用的全局locale作為默認的locale。如果你不顯式的把一個流和一個特定的locale綁定在一起,那么這個流對象就默認和一個在它被創建時的那個全局的locale綁定。
C下全局locale所能做的,C++全局locale也能做到。在程序啟動一旦開始,程序就激活了本地locale。換言之,本地locale被激活作為global locale,并作為locale快照,之后所有的工作都依賴這個locale。以下的代碼描述了這個過程:
std::locale::global(std::locale("")); //1
...
std::string t = print_date(today, std::locale()); //2
...
std::locale::global(std::locale("Fr_CH")); //3
...
std::cout << something; //4
//1 設置本地locale作為全局locale
//2 總是使用全局locale快照作為你當前使用的locale對象。假設函數print_date()是格式化日期的。為了格式化日期,你將要提供一個全局locale的快照給函數print_date()。
//3 切換全局locale到French全局locale
//4 注意在這個例子中,標準流cout仍然是跟classic locale(標準的locale)綁定的,因為在程序啟動的時候,std::cout就被創建出來了。改變全局locale不會影響先前已經存在的流的locales。如果你想讓一個新的全局locale綁定到cout上,你應該在調用完std::locale::global()之后調用stf::cout.imbue(locale())。
24.3.3 C locale和C++ locales之間的聯系
C locale和C++ locale是完全獨立的。然而,C++ locale對象是有個名字的,通過std::locale::global()使locale對象變成全局locale會引起C locale改變,這個改變會通過調用std::setlocale()。當它發生時,在C++程序里,locale敏感的C函數會使用變化了的C locale。
在一個C程序里,是沒有辦法改變C++ locale的。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。