[英]How to avoid integer promotion in C?
尚不清楚如何使用寬字符API用C編寫可移植代碼。 考慮以下示例:
#include <locale.h>
#include <wchar.h>
#include <wctype.h>
int main(void)
{
setlocale(LC_CTYPE, "C.UTF-8");
wchar_t wc = L'ÿ';
if (iswlower(wc)) return 0;
return 1;
}
使用-Wconversion選項在gcc-6.3.0中進行編譯會給出以下警告:
test.c: In function 'main':
test.c:9:16: warning: conversion to 'wint_t {aka unsigned int}' from 'wchar_t {aka int}' may change the sign of the result [-Wsign-conversion]
if (iswlower(wc)) return 0;
^
為了擺脫這一警告的,我們投來(wint_t)
像iswlower((wint_t)wc)
但這是不可移植。 下面的示例演示了為什么它不可移植。
#include <stdio.h>
/* this is our hypothetical implementation */
typedef signed int wint_t;
typedef signed short wchar_t;
#define WEOF ((wint_t)0xffffffff)
void f(wint_t wc)
{
if (wc==WEOF)
printf("BUG. Valid character recognized as WEOF. This is due to integer promotion. How to avoid it?\n");
}
int main(void)
{
wchar_t wc = (wchar_t)0xffff;
f((wint_t)wc);
return 0;
}
我的問題是:如何使此示例具有可移植性,同時避免出現gcc警告。
為了簡單起見,我將假設我正在討論的平台/實現具有以下特征:
int
是32位 short
是16位 我也將使用C99作為參考,因為這是我已經打開的內容。
該標准說,這些類型/宏必須滿足以下條件:
wint_t
必須至少具有一個與擴展字符集的任何成員都不對應的值(7.24.1 / 2) WEOF
的值與擴展字符集的任何成員都不對應(7.24.1 / 3) wchar_t
可以表示最大擴展字符集(7.17 / 2)的所有值 請記住,根據C標准對“值”的定義, (short int) 0xffff
的值與(int) 0xffffffff
的值相同 -也就是說,它們都具有值-1
(假設在此答案的開頭)。 通過標准對整數促銷(6.3.1.1)的描述可以清楚地看出這一點:
如果一個int可以表示原始類型的所有值,則該值將轉換為int; 否則,它將轉換為unsigned int。 這些稱為整數促銷。 整數促銷未更改所有其他類型。
整數促銷保留包括符號在內的價值。
我相信,當您將這些元素組合在一起時,似乎WEOF
的值為-1
,那么擴展字符集中的任何項目都不能值為-1
。 我認為這意味着在您的實現示例中,要么wchar_t
必須是無符號的(如果它仍然是16位類型),要么(wchar_t) 0xffff
不能是有效字符。
但是我最初忘記的另一種選擇(可能是您的示例實現的最佳解決方案)是,標准在腳注中指出“宏WEOF
值可能與EOF
值不同,不必為負”。 因此,可以通過使WEOF == INT_MAX
來解決實現問題。 這樣,它不能具有與任何wchar_t
相同的值。
我認為可能與有效字符值重疊的WEOF
值是我認為可能在實際實現中出現的一個值(即使該標准似乎禁止了它),它類似於關於EOF
可能與某些值具有相同值的問題。有效的帶符號字符值。
對於大多數可以返回WEOF
來指示某種問題的(全部?)函數,可能有意思的是,標准要求該函數設置有關錯誤或條件的一些附加指示(例如,將errno
為特定值,或在流上設置文件結束指示符)。
需要注意的另一件事是,根據我的理解,0xffff在UCS-2或UTF-16中是非字符(不知道可能存在的其他任何16位編碼)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.