为什么`putchar()`、`fputc()`和`putc()`的参数类型不是`char`?

3
有人知道为什么putchar()fputc()putc()的参数类型不是char,但是putwchar()fputwc()putwc()的参数类型却是wchar_t吗?请参见这里这里

正如您提供的第二个链接所述,这是因为wchar_t必须能够存储EOF等元值,而char则不需要。因此,那些原本使用char的地方需要改用int,以便传输元值。这在C语言中相当常见。 - LambdaBeta
@LambdaBeta,第二个链接的第一句话与答案的其余部分完全相矛盾,并且事实上是错误的。 - n. m.
@LambdaBeta,为什么会引入wint_t呢? - Igor Liferenko
@IgorLiferenko: wint_t的引入是因为当传递给printf()等函数时,wchar_t可能会受到“默认提升”规则的影响。标准指出,wint_t可能与wchar_t是相同类型,但如果wchar_t是一个(16位)short,那么wint_t可能是一个(32位)int类型。 - Jonathan Leffler
@JonathanLeffler:“当传递给printf()等函数时,wchar_t可能是受'默认提升'规则约束的类型。”请将此内容与示例添加到http://stackoverflow.com/questions/40601645/how-to-change-wchar-h-to-make-wchar-t-the-same-type-as-wint-t中,以便我可以点赞。 - Igor Liferenko
我已将“默认推广”规则添加到答案中 - 引用标准。 - Jonathan Leffler
2个回答

7
答案是“遗留”(或“历史”)。在C90标准之前,没有函数原型,所有函数的所有参数都受到默认提升规则的影响,因此char会自动作为int传递(short也会被提升为intfloat也会被提升为double,无符号类型同理)。标准不能破坏现有代码,因此保留了这些函数的类型。实际上几乎没有什么区别。即使传递超出范围的值,您传递的值也将被视为字符类型。 fputc(int c, FILE *stream)的规范说明如下:

fputc函数将由c指定的字符(转换为unsigned char)写入到由stream指向的输出流中...

默认提升规则

§6.5.2.2 函数调用

¶6 如果表示被调用函数的表达式具有不包括原型的类型,则对每个参数执行整数提升,并将类型为float的参数提升为double。这些被称为默认参数提升。

¶7 …函数原型声明符中的省略号表示在最后一个声明的参数之后停止参数类型转换。默认参数提升对尾随参数执行。

整数提升在§6.3.1中定义。

¶2 下列内容可在表达式中使用,其所属的类型可以是intunsigned int:

  • 一个整型类型(但不是intunsigned int)的对象或表达式,其整型转换等级小于或等于intunsigned int的等级。
  • _Boolintsigned intunsigned int类型的位域。

如果一个int类型可以表示原始类型的所有值(对于位域,则由宽度限制),则将该值转换为int;否则,将其转换为unsigned int。这被称为整数提升58)。所有其他类型都不受整数提升的影响。

¶3 整数提升保留了值,包括符号。如前所述,“普通”的char类型是否被视为带符号是由实现定义的。

58) 整数提升仅应用于:作为通常算术转换的一部分,某些参数表达式,一元+-~运算符的操作数,以及移位运算符的两个操作数,如各自的子句中所指定的。

整数等级在第10条中的¶1节中定义为10个要点。


@chux 我已经检查过了,确实 putchar(EOF); 输出的是 0xff - Igor Liferenko
@IgorLiferenko:是的,但检查它在您的系统上的运行情况并不能真正证明什么。标准指出putchar(c)等价于putc(c, stdout),而putc(c, stdout)又非常接近fputc(c, stdout)fputc被指定将其第一个参数转换为unsigned charEOF通常为-1(尽管这并不保证),将该值转换为unsigned char则会得到UCHAR_MAX,通常为0xff。无论如何,将EOF传递给putchar()也没有太多意义。 - Keith Thompson
@KeithThompson,这是为了说明已删除的评论,即无论传递给fputc()的参数是int还是signed char变量,它都会被转换为unsigned char。我使用EOF作为负数的角色,因为在我的系统上它被认为是-1 - Igor Liferenko

0

我认为Jonathan的回答太简单了。事情稍微有些合理。我认为处理单个字符的库函数没有一个是使用char(只使用int)的,因为即使其中一些不使用EOF,我们也无法将其类型设置为char,否则会收到类型转换警告。

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

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

因为人们通常将类型转换为无符号字符以确保代码的可移植性,考虑到 char 的有符号性是未定义的。

所以唯一的选择就是将其设为 int


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接