This is the mail archive of the glibc-bugs@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Bug libc/20639] Inconsistency in definitions of fputwc(), putwc() and putwchar() in glibc


https://sourceware.org/bugzilla/show_bug.cgi?id=20639

--- Comment #7 from Igor Liferenko <igor.liferenko at gmail dot com> ---
Hi all,

I figured it out.

We may pass a wchar_t variable to putwchar(), putwc() or fputwc() - it does not
have to be wint_t. Consider example 1):

  wchar_t wc = L'a';
  putwchar(wc);

Analogous non wide-character example 2):

  char c = 'b';
  putchar(c);

OTOH, we may read a character from a file, like in example 3):

  int c = getchar();
  putchar(c);

Anyway, why do we need to use type "int" for a character? Because EOF value
cannot
be used with "char", as char does not have free "slots" to carry EOF value.
After
"int" value is compared with "EOF", it is guaranteed to hold one of those
values which "char" can hold. But its type remains "int" anyway.

So, why compiler does not give any conversion warnings in example 2) and 3)?
Why we may pass arguments of type "int" and "char" to putchar()? Answer:
because
when we pass to putchar() the argument of type "char", "char" value is
*promoted*
to "int" value.

In C99, integer promotion is defined in following rule:

  If an int can represent all values of the original type, the value is
converted
  to an int; otherwise, it is converted to an unsigned int. These are called
the
  integer promotions. All other types are unchanged by the integer promotions.

The situation is different for wchar_t and wint_t. Amendment 1 to C90 says
this:

  Currently, an existing implementation could have wchar_t be int and wint_t be
  long, and default promotions would not change int to long. Basically, this is
due
  to wchar_t and wint_t being typedefs. Hence, we will not now have wchar_t be
  promoted to wint_t.

So, the functions putwchar(), putwc() and fputwc() must have the argument of
type
either "wchar_t" or "wint_t", and we must be able to pass arguments of type
"wchar_t" and "wint_t" to these functions.

We have two variants:

1) The argument of putwchar(), ... will be of type "wchar_t". In this case we
would
have to cast wint_t to wchar_t.

2) The argument of putwchar(), ... will be of type "wint_t". In this case we
would
have to cast wchar_t to wint_t.

If we have to typecast anyway, it is more logical to choose variant 1), because
only
the value of wchar_t will be used in functions putwchar(), putwc() and
fputwc().
The value of wint_t is used only for checking WEOF, and if it is WEOF, it is
never
passed to these functions.

Likewise, only the value of "char" will be used in putchar(), putc() and
fputc().
The reason why putchar(), putc() and fputc() take argument of type "int" is
that
it works for both "int" and "char", without any extra typecasting.

But there is another question: why if in glibc wchar_t is always 4 bytes,
wchar_t
and wint_t are not one and the same type? There is enough place in 4 bytes to
hold
all ISO 10646 values and WEOF, not depending whether the type is signed or
unsigned,
as explained in comment #5.

So, the example from the first post should be changed to this:

    #include <locale.h>
    #include <wchar.h>
    int main(void)
    {
      setlocale(LC_CTYPE, "en_US.UTF-8");
      putwchar((wchar_t)getwchar());
      return 0;
    }

Now there are no compiler warnings when -Wconversion is used.
The bugreport may be closed.

-- 
You are receiving this mail because:
You are on the CC list for the bug.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]