[英]Why there are no “unsigned wchar_t” and “signed wchar_t” types?
char的簽名不是標准化的。 因此,有signed char
和unsigned char
類型。 因此,使用單個字符的函數必須使用可以包含signed char和unsigned char的參數類型(此類型被選擇為int
),因為如果參數類型是char
,我們將從編譯器獲取類型轉換警告(如果在這樣的代碼中使用-Wconversion):
char c = 'ÿ';
if (islower((unsigned char) c)) ...
warning: conversion to ‘char’ from ‘unsigned char’ may change the sign of the result
( 這里我們考慮如果islower()的參數類型為char會發生什么 )
而沒有明確類型轉換使其工作的事情是從char
到int
自動升級。
此外,引入了wchar_t
的ISO C90標准沒有說明關於wchar_t
表示的任何具體內容。
glibc引用的一些引用:
將
wchar_t
定義為char
是合理的
如果
wchar_t
定義為char
則由於參數提升,類型wint_t
必須定義為int
。
因此, wchar_t
可以很好地定義為char
,這意味着必須應用類似寬字符類型的規則,即,可能存在wchar_t
為正的實現,並且可能存在wchar_t
為負的實現。 unsigned wchar_t
,必須存在unsigned wchar_t
和signed wchar_t
類型(出於與unsigned char
和signed char
類型相同的原因)。
私有通信顯示允許實現僅支持> = 0值的寬字符(與wchar_t
的簽名無關)。 誰知道這意味着什么? 瘦是否意味着當wchar_t
是16位類型(例如)時,我們只能使用15位來存儲寬字符的值? 換句話說,符號擴展的wchar_t
是否為有效值? 另見這個問題 。
此外,私人通信顯示標准要求wchar_t
任何有效值必須由wint_t
表示。 這是真的嗎?
考慮這個例子:
#include <locale.h>
#include <ctype.h>
int main (void)
{
setlocale(LC_CTYPE, "fr_FR.ISO-8859-1");
/* 11111111 */
char c = 'ÿ';
if (islower(c)) return 0;
return 1;
}
為了使它可移植,我們需要轉換為'(unsigned char)'。 這是必要的,因為char
可能是等效的signed char
,在這種情況下,設置頂部位的字節在轉換為int
時將被符號擴展,從而產生超出unsigned char
范圍的值。
現在,為什么這種情況與寬字符的以下示例不同?
#include <locale.h>
#include <wchar.h>
#include <wctype.h>
int main(void)
{
setlocale(LC_CTYPE, "");
wchar_t wc = L'ÿ';
if (iswlower(wc)) return 0;
return 1;
}
我們需要在這里使用iswlower((unsigned wchar_t)wc)
,但是沒有unsigned wchar_t
類型。
為什么沒有unsigned wchar_t
和signed wchar_t
類型?
UPDATE
標准是否保證在以下兩個程序中轉換為unsigned int
和int
是正確的? (我只是將wint_t
和wchar_t
替換為glibc中的實際含義)
#include <locale.h>
#include <wchar.h>
int main(void)
{
setlocale(LC_CTYPE, "en_US.UTF-8");
unsigned int wc;
wc = getwchar();
putwchar((int) wc);
}
-
#include <locale.h>
#include <wchar.h>
#include <wctype.h>
int main(void)
{
setlocale(LC_CTYPE, "en_US.UTF-8");
int wc;
wc = L'ÿ';
if (iswlower((unsigned int) wc)) return 0;
return 1;
}
為什么沒有未簽名的wchar_t和簽名的wchar_t類型?
因為C的寬字符處理設施被定義為不需要它們。
更詳細的,
char的簽名不是標准化的。
確切地說,“實現應該將char定義為具有與signed char或unsigned char相同的范圍,表示和行為。” (C2011,6.2.5 / 15)
因此,有
signed char
和unsigned char
類型。
“因此”意味着因果關系,這很難說清楚,但當你想要處理數字而不是字符時,肯定signed char
和unsigned char
更合適。
因此,使用單個字符的函數必須使用可以包含signed char和unsigned char的參數類型
一點都不。 使用單個字符的標准庫函數可以根據char
類型輕松定義,無論該類型是否已簽名,因為庫實現確實知道其簽名。 如果這是一個問題,那么它也同樣適用於字符串函數 - char
將是無用的。
你的getchar()
示例是不合適的。 它返回int
而不是字符類型,因為它需要能夠返回與任何字符都不對應的錯誤指示符。 此外,您提供的代碼與附帶的警告消息不對應:它包含從int
到unsigned char
轉換,但沒有從char
到unsigned char
轉換。
其他一些字符處理函數接受int
參數或返回int
類型的值,以便與getchar()
和其他stdio函數兼容,並且出於歷史原因。 在以前的日子里,你實際上根本無法傳遞一個char
- 它總是被提升為int
,這就是函數將(並且必須)接受的東西。 以后不能改變論證類型,語言的演變。
此外,引入了
wchar_t
的ISO C90標准沒有說明關於wchar_t
表示的任何具體內容。
C90不再具有真正的相關性,但毫無疑問它與C2011(7.19 / 2)非常類似,它將wchar_t
描述為
一個整數類型,其值范圍可以表示支持的語言環境[...]中指定的最大擴展字符集的所有成員的不同代碼。
來自glibc引用的引用是非權威的,除了可能只對glibc。 它們在任何情況下都是評論,而不是規范,並且不清楚為什么你提出它們。 當然,至少第一個是正確的。 參考標准,如果給定實現支持的語言環境中指定的最大擴展字符集的所有成員都可以放入char
那么該實現可以將wchar_t
定義為char
。 這種實現過去比現在更常見。
你問幾個問題:
私有通信顯示允許實現僅支持> = 0值的寬字符(與
wchar_t
的簽名無關)。 誰知道這意味着什么?
我認為這意味着,與您溝通的人不會知道他們在談論什么,或者他們所談論的內容與C標准的要求不同。 您會發現在實踐中 ,字符集僅使用非負字符代碼定義,但這不是C標准所放置的約束。
瘦是否意味着當
wchar_t
是16位類型(例如)時,我們只能使用15位來存儲寬字符的值?
C標准沒有說或暗示。 您可以將任何支持的字符的值存儲在wchar_t
。 特別是,如果實現支持包含超過32767的字符代碼的字符集,則可以將它們存儲在wchar_t
。
換句話說,符號擴展的wchar_t是否為有效值?
C標准沒有說或暗示。 它甚至沒有說wchar_t
是否是帶符號的類型(如果沒有,那么符號擴展對它來說毫無意義)。 如果它是帶符號的類型,則無法保證在某些受支持的字符集中對表示字符的值進行符號擴展(該值原則上可以為負值)將生成一個值,該值也表示該字符中的字符設置,或任何其他支持的字符集。 將1添加到wchar_t
值也是如此。
此外,私人通信顯示標准要求
wchar_t
任何有效值必須由wint_t
表示。 這是真的嗎?
這取決於“有效”的含義。 標准說wint_t
是默認參數提升的未更改的整數類型,它可以包含與擴展字符集的成員對應的任何值,以及至少一個與擴展字符集的任何成員不對應的值。
(C2011,7.29.1 / 2)
wchar_t
必須能夠在任何受支持的語言環境中保存與擴展字符集的成員相對應的任何值。 wint_t
必須能夠保存所有這些值。 但是, wchar_t
可以表示與任何支持的字符集中的任何字符都不對應的值。 這些值在類型可以表示它們的意義上是有效的。 wint_t
不需要能夠表示這樣的值。
例如,如果任何支持的語言環境的最大擴展字符集使用的字符代碼最多但不超過32767,那么實現可以自由地將wchar_t
實現為無符號的16位整數,並將wint_t
為帶符號的16位整數。 wchar_t
表示的與擴展字符不對應的值因此不能由wint_t
表示(但是wint_t
仍然有許多候選者,其所需的值與任何字符都不對應)。
關於字符和寬字符分類功能,唯一的答案是差異僅僅來自不同的規范。 char
分類函數被定義為使用與定義返回的getchar()
相同的值 - -1或者必要時轉換為unsigned char
的字符值。 另一方面,寬字符分類函數接受wint_t
類型的參數,它可以表示所有寬字符的值不變,因此不需要轉換。
你在這方面聲稱
我們需要在這里使用
iswlower((unsigned wchar_t)wc)
,但是沒有unsigned wchar_t
類型。
不,也許。 您不需要將wchar_t
參數轉換為iswlower()
到任何其他類型,特別是,您不需要將其轉換為顯式無符號類型。 廣泛的字符分類功能與這方面的常規字符分類功能不同,它的設計是為了后見之明。 對於unsigned wchar_t
,C不需要存在這樣的類型,因此可移植代碼不應該使用它,但它可能存在於某些實現中。
標准是否保證在以下兩個程序中轉換為unsigned int和int是正確的? (我只是將wint_t和wchar_t替換為glibc中的實際含義)
該標准沒有提到一般的符合實現的那種。 但是,我想你的意思是要具體詢問符合wchar_t
為int
且wint_t
為unsigned int
。
在這樣的實現,因為它沒有考慮的可能性,你的第一個程序是有缺陷的getwchar()
返回WEOF
。 將WEOF
轉換為類型wchar_t
,如果這樣做不會導致信號被引發,則不能保證產生對應於任何寬字符的值。 因此,將此類轉換的結果傳遞給putwchar()
不會顯示已定義的行為。 此外,如果WEOF
與相同的值定義UINT_MAX
(這是不被表示的int
),那么該值的轉換int
具有實現定義的行為獨立於的putwchar()
調用。
另一方面,我認為你正在努力的關鍵點是,如果getwchar()
在第一個程序中返回的值不是WEOF
,那么它保證是通過轉換為wchar_t
而保持不變的值。 您的第一個程序將在該情況下執行,但是轉換為int
(或wchar_t
)是不必要的。
類似地,第二個程序是正確的,只要寬字符文字對應於適用的擴展字符集中的字符,但是轉換是不必要的並且不做任何改變。 這種文字的wchar_t
值保證可以通過類型wint_t
表示,因此轉換會更改其操作數的類型,但不會更改值。 (但是如果文字與擴展字符集中的字符不對應,則行為是實現定義的。)
第三方面,如果您的目標是編寫嚴格一致的代碼,那么正確的事情,以及這些特定寬字符函數的預期使用模式,將是這樣的:
#include <locale.h>
#include <wchar.h>
int main(void)
{
setlocale(LC_CTYPE, "en_US.UTF-8");
wint_t wc = getwchar();
if (wc != WEOF) {
// No cast is necessary or desirable
putwchar(wc);
}
}
還有這個:
#include <locale.h>
#include <wchar.h>
#include <wctype.h>
int main(void)
{
setlocale(LC_CTYPE, "en_US.UTF-8");
wchar_t wc = L'ÿ';
// No cast is necessary or desirable
if (iswlower(wc)) return 0;
return 1;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.