如何避免C中的整数提升?

目前尚不清楚如何使用宽字符API在C中编写可移植代码。 考虑这个例子:

#include  #include  #include  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) ,但这是iswlower((wint_t)wc)移植的。 以下示例说明了为什么它不可移植。

 #include  /* 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位编码)。