ANSI C:为什么字符函数接受 int 参数而不是 char 参数?

11
为什么字符函数接受int参数而不是char参数?
<ctype.h>

int isalnum(int c); 
int isalpha(int c); 
int iscntrl(int c); 
int isdigit(int c); 
int isgraph(int c); 
int islower(int c); 
int isprint(int c); 
int ispunct(int c); 
int isspace(int c); 
int isupper(int c); 
int isxdigit(int c); 
int tolower(int c); 
int toupper(int c); 

我怀疑答案类似于这里给出的答案。在C语言中,字符字面量的类型是int - Cody Gray
@Cody:这两个决定可能是相关的,因为在 C 语言中对字符进行“计算”的正确数据类型是 int。但是,字面值与这些函数参数具有相同的类型并不像看起来那么简单。您可以编写 isalnum('a'),但不能保证能编写 isalnum(CHAR_MIN),或者对应于您实现中的 CHAR_MIN 的任何字符文字,因为它可能是负数。为了与这些函数匹配,字符字面值确实需要具有 unsigned 类型,但将它们转换为 char 会潜在地出现问题。 - Steve Jessop
4个回答

12

在C语言中,字符和整数密切相关。

当你从输入流接收一个字符时,它必须能表示每个字符以及文件结束符号。

这意味着char类型不够大,因此使用更宽的类型。

C99理论文档指出:

由于这些函数通常主要用作宏,因此它们的域被限制为可在无符号char中表示的小正整数,加上EOF的值。EOF传统上为-1,但可以是任何负整数,并且可区分于任何有效的字符代码。因此,可以通过将参数用作属性小数组的索引来高效地实现这些宏。

标准本身有这样的说法:

头文件<ctype.h>声明了几个用于分类和映射字符的有用函数。在所有情况下,参数都是int类型,其值应表示为unsigned char或等于宏EOF的值。如果参数具有任何其他值,则行为未定义。


1
下一个规模更大的数据类型实际上是“short”。但是,当这些被发明时,“short”将会像“char”一样被提升为“int”。 - Jerry Coffin
@JerryCoffin 你的意思是什么?无论何时在表达式中使用,所有的short类型都会被提升为int类型。 - Lundin
@AmirSaniyan:while ((mychar = tolower(getchar()) != EOF) { /* do stuff */ } 从技术上讲,非ASCII值会返回未定义的值,但是“这种行为是未定义的”有什么时候能阻止任何人依赖它呢? - tbert
@Jerry:更重要的是,在这些东西被发明的时候,许多地方的shortchar大小相同。虽然标准没有明确要求,但在几乎所有地方,int都比char大。如果它们大小相同,实现者将需要一个特殊的“保留”负值,它不是执行字符集中的代码点,并且永远无法从任何类型的输入(包括例如二进制文件流)中读取,并将其用作EOF。我不确定这是否合法,因为这意味着有一个char值无法写入文件并读回。 - Steve Jessop
@SteveJessop:哪个编译器使char和short大小相同?我很确定AT&T编译器和Whitesmiths都没有。我记得有很多早期的编译器(例如BDS C)根本没有short,但没有一个将其大小与char相同。 - Jerry Coffin
@Jerry:对不起,我很困惑。出于某种原因,我认为short在8位和16位系统上通常是8位,但这当然不符合规范。考虑一下,我不确定我是否真的使用过short - Steve Jessop

5

在C语言刚被发明时,函数参数没有编译时检查。如果调用foo(bar,boz),并且barbozint类型,编译器会将两个int值推送到堆栈上,调用foo,并希望它期望得到两个int值。由于小于int的整数类型在评估表达式时会提升为int,因此在原型发明之前编写的C函数无法传递任何更小的整数类型。


3

除了普通字符值外,它们还需要接受EOF。它们也早于函数原型的发明。当时,没有办法将char传递给函数,它总是先被提升为int


0

是的,这可能是为了适应EOF而设计的,它始终是一个非字符值,虽然不同系统的EOF确切值可能会有所不同,但它永远不会与任何字符代码相同。


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