cportabilitywchar-twidechar

How to avoid integer promotion in C?


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.


Solution

  • 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))