It is not clear how to write portable code in C, using wide-character API. Consider this example:
#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;
}
Compiling it with gcc-6.3.0 using -Wconversion option gives this warning:
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;
^
To get rid of this warning, we cast to (wint_t)
, like iswlower((wint_t)wc)
, but this is unportable.
The following example demonstrates why it is unportable.
#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;
}
My question is: how to make this example portable, and at the same time avoid the gcc warning.
How to avoid integer promotion in C?
iswlower(wc)
does not involve an integer promotion.
Integer promotions do not change the value and the warning is about a value change.
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]
iswlower(wc)
may incur a conversion. It did in OP's case, from int
to unsigned
.
Other answers address OP's final "My question is: how to make this example portable, and at the same time avoid the gcc warning.", but it remains a conversion issue, not a integer promotion one.
To quiet the warning without a cast, code could use a WCHAR_MAX
mask.
Of course if wc < 0
, information is lost.
#include <stdint.h>
// Useful when wc >= 0.
if (iswlower(WCHAR_MAX & wc))