为啥 putchar、toupper、tolow 等采用 int 而不是 char?

Posted

技术标签:

【中文标题】为啥 putchar、toupper、tolow 等采用 int 而不是 char?【英文标题】:Why putchar, toupper, tolower, etc. take a int instead of a char?为什么 putchar、toupper、tolow 等采用 int 而不是 char? 【发布时间】:2013-07-01 10:18:48 【问题描述】:

在 C 中,字符串是 char (char *) 的数组,字符通常存储在 char 中。我注意到 libC 中的一些函数将整数而不是字符作为参数。

例如,让我们以函数toupper()tolower() 为例,它们都使用int。手册页说:

如果 c 不是无符号字符值或 EOF,则这些值的行为 函数未定义。

我的猜测是,inttouppertolower 能够处理 unsigned charEOF。但实际上EOF 在实践中是(关于它的值是否有任何规则?)一个可以用char 存储的值,并且由于这些函数不会将EOF 转换为其他东西,我想知道为什么toupper 不简单地将字符作为参数。

无论如何,为什么我们需要接受不是字符的东西(例如EOF)?有人可以给我一个相关的用例吗?

这与fputcputchar 类似,它们也采用int,无论如何都会转换为unsigned char

我正在寻找该选择的确切动机。我想被说服,我不想回答我不知道有一天是否有人问我。

【问题讨论】:

我不知道EOF 必须适合char 的任何规则,我可以向您保证char 不保证被签名,这使您讨论使用@987654343 @ 而不是 unsigned char 似乎是错误的。你的意思是signed char 你看过这些函数的实现吗?我认为int 参数是出于优化目的,因为它的字节大小非常适合处理器寄存器的大小。反过来,一个字节的char变量必须在幕后转换为int,这个操作需要一些处理器时间来处理。 阅读:Definition of EOF and how to use it effectively 【参考方案1】:

C11 7.4

标题<ctype.h> 声明了几个对分类和映射有用的函数 人物。在所有情况下,参数都是一个 int,其值应为 可表示为无符号字符或应等于 宏EOF。如果参数有任何其他值,则行为是 未定义。

C11 7.21.1

EOF

扩展为整数常量表达式,类型为 int 和 负值,...

C 标准明确规定 EOF 始终是具有负值的 int。而且,默认char类型的签名是实现定义的,所以它可能是无符号的,不能存储负值:

C11 6.2.5

如果基本执行字符集的成员存储在 char 中 对象,它的值保证是非负的。如果有其他 字符存储在 char 对象中,结果值为 实现定义,但应在值的范围内 可以用那种类型来表示。

【讨论】:

我的一个问题是:为什么将一个字母转换成另一个字母的函数应该接受不是字母的东西? (包括 EOF) 另一个答案已经回答了你的问题(为什么像tolower() 这样的函数需要接受不是字母的东西,例如EOF)——因为在像tolower(ch = getchar()) 这样的惯用情况下, ch,这是一个int,很可能是EOF,因此希望tolower可以接受EOF【参考方案2】:

BITD编码方式包括:

/* example */
int GetDecimal() 
  int sum = 0;
  int ch;
  while (isdigit(ch = getchar()))  /* isdigit(EOF) return 0 */
    sum *= 10;
    sum += ch - '0';
    
  ungetc(ch, stdin);  /* If c is EOF, operation fails and the input stream is unchanged. */
  return sum;

ch 与 EOF 的值可以用于各种功能,如 isalpha()tolower()

这种风格导致putchar(EOF) 出现问题,我怀疑这与putchar(255) 相同。

由于各种原因,该方法今天不鼓励。首选以下各种型号。

int GetDecimal() 
  int ch;
  while (((ch = getchar()) != EOF)) && isdigit(ch)) 
    ...
  
  ...

【讨论】:

我已经 +1 你的使用示例的答案。但是正如你所说,这是不鼓励的,那么为什么isdigit 应该接受不是字符的东西? @Maxime 我确信isdigit() 接受-1 是历史性的。从概念上讲,不难将 EOF 视为另一个 charisthis...() 函数通常使用 256 字节数组实现,使 257 字节数组也接受 EOF (-1) 是微不足道的。由于它很容易并且可以编写更紧凑的代码,因此当紧凑的代码具有更高的价值时,它是一个很好的扩展。现在,随着代码维护的价值不断增加,这个成语已经失宠了。【参考方案3】:

如果 c 不是 unsigned char 值或 EOF,则这些函数的行为是未定义的。

但是EOF 在 C 中是否定的int,并且某些平台(嗨 ARM!)具有与 unsigned char 相同的 char

【讨论】:

是的,但是在重要的地方,C 标准说“无符号字符或 EOF”。

以上是关于为啥 putchar、toupper、tolow 等采用 int 而不是 char?的主要内容,如果未能解决你的问题,请参考以下文章

C语言中 toupper()和tolower()用法?请大神详述 谢谢!!!

在调用 toupper()、tolower() 等之前,我是不是需要转换为 unsigned char?

linq 不区分大小写(没有 toUpper 或 toLower)

C函数tolower,与toupper

ccf 201409-3 字符串匹配(toupper,tolower)

C#慎用ToLower和ToUpper,小心把你的系统给拖垮了