目前尚不清楚如何使用宽字符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警告。
答案 0 :(得分:1)
为了简单起见,我将假设我讨论的平台/实现具有以下特征:
int
是32位short
是16位我也会使用C99作为参考,因为它是我打开的。
标准规定对于这些类型/宏必须满足以下条件:
wint_t
必须至少有一个与扩展字符集的任何成员不对应的值(7.24.1 / 2)WEOF
的值与扩展字符集的任何成员(7.24.1 / 3)不对应wchar_t
可以表示最大扩展字符集(7.17 / 2)的所有值请注意,根据C标准对&#34;值&#34;的定义,(short int) 0xffff
的值与<{>相同的值为{{ 1}} - 也就是说它们都具有值(int) 0xffffffff
(给出本答案开头所述的假设)。标准对整数促销的描述(6.3.1.1)清楚地表明了这一点:
如果int可以表示原始类型的所有值,则该值将转换为int;否则,它将转换为unsigned int。这些被称为整数促销。所有其他类型都不会被整数促销更改。
整数促销保留包括符号在内的值。
我相信当你组合这些元素时,如果-1
的值为WEOF
,那么扩展字符集中的任何项都不能具有值-1
。我认为这意味着在您的实现示例中,-1
必须是无符号的(如果它仍然是16位类型)或wchar_t
不能是有效字符。
但是我最初忘记的另一个替代方案(并且可能是您的示例实现的最佳解决方案)是标准在脚注中指出宏(wchar_t) 0xffff
的值可能与WEOF
的不同,不一定是否定的&#34;。因此,您可以通过制作EOF
来解决您的实施问题。这样它就不能具有与任何WEOF == INT_MAX
相同的值。
可能与有效字符值重叠的wchar_t
值是我认为可能在实际实现中出现的值(即使标准似乎禁止它),并且它类似于已经存在的问题提出WEOF
可能与某些有效的签名字符值具有相同的值。
对于可以返回EOF
以指示某种问题的大多数(所有?)函数,可能会感兴趣,标准要求函数设置一些关于错误或条件的附加指示(例如,将WEOF
设置为特定值,或在流上设置文件结束指示符。
另外需要注意的是,我的理解是0xffff是UCS-2或UTF-16中的非字符(不知道可能存在的任何其他16位编码)。