4

The ISO C90 standard, where wchar_t was introduced, does not say anything specific about the representation. It only requires that this type is capable of storing all elements of the basic character set.

Which means that wchar_t may well be of type char, and wint_t may be of type int. Further, in some implementations wchar_t may be signed, and in some - unsigned. How is the situation different from putchar()?

For comparison, the argument of putchar(), putc() and fputc() was chosen to be int.

I think that none of the library functions which handle single characters work with char (only with int), because even though some of them do not use EOF (like putchar()), we cannot make its type char, because if it was char, and we typecast to unsigned char (the signedness of char is not standardized), there would be type conversion warnings like

void f(char c) { ...
...
int x = 't';
f((unsigned char)x);
...

warning: conversion to ‘char’ from ‘unsigned char’ may change the sign of the result

So the only option was to make it int, which can hold both signed and unsigned char.

Although the argument is automatically converted to unsigned char by putchar() even if it was passed as int or signed char, nothing of the sort is done in putwchar().

So, why fputwc(), putwc() and putwchar() take wchar_t, not wint_t? Seems like a flaw in the standard. Am I missing something obvious?

See also Why islower() and friends are required to handle EOF? and Why argument type of putchar(), fputc() and putc() is not char? and Inconsistency in definitions of fputwc(), putwc() and putwchar() in glibc


UPDATE

some quotations from glibc reference

if wchar_t is defined as char the type wint_t must be defined as int due to the parameter promotion.

it would be legitimate to define wchar_t as char

Is fact, these functions had correct interfaces in "ISO Working Paper SC22/WG14/N204 dated 31st March 1992" (which is the final draft before publishing "ISO/IEC 9899:1990/Amendment 1:1995"), but they were changed in "ISO/IEC 9899:1990/Amendment 1:1995". See here http://www.unix.org/version2/whatsnew/login_mse.html

Community
  • 1
  • 1
Igor Liferenko
  • 1,499
  • 1
  • 13
  • 28

1 Answers1

2

It is an interesting question, but unfortunately I think that the answer is just for historical reasons. The remainder of this answer is only my opinion, I have no references for it.

The fputc family exists since the first versions of K&R C, where prototypes for functions did not even exist: you should know what parameter types a function accepted and no implicit conversion could occur in function calls. As the fgetc family was returning an int, it was decided that the symmetric fputc one will take an int as parameter to allow the following construct:

fputc(fgetc(fd1), fd2);

If fputc had taken a char, it should have been written (K&R C): fputc((char) fgetc(fd1), fd2);.

But now, only dinosaurs can remember from K&R and implicit conversions do occur in function calls. So when the wide character set functions were added to the standard library, it was decided to only pass the part that was used to avoid a double conversion wchar_t -> wint_t -> wchar_t because only a wchar_t is used. And it is explicit in fputs definition (emphasize mine):

int fputc(int c, FILE *stream);
Description: The fputc function writes the character specified by c (converted to an unsigned char) to the output stream pointed to by stream...

So it is not very coherent, but I suppose that nobody really thought necessary to change the definition of the old fputc family functions...

Toby Speight
  • 27,591
  • 48
  • 66
  • 103
Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
  • The definition of `fputc` is correct, it need not be changed - read the rationale in OP and here http://stackoverflow.com/a/40732303/1487773/ And `fputwc` is incorrect - for the very same reason (because wchar_t is no different from char - see OP) – Igor Liferenko Nov 23 '16 at 00:55
  • All functions for wide characters must be analogous to functions for ordinary characters, excluding the cases where automatic promotion plays the role. – Igor Liferenko Nov 23 '16 at 01:38