【问题标题】:Does isspace() accept getchar() values?isspace() 是否接受 getchar() 值?
【发布时间】:2017-11-05 07:07:19
【问题描述】:

isspace() 在输入为representable as unsigned char 或等于EOF 时有效。

getchar() 从标准输入读取下一个字符。

getchar()!=EOF;是否所有getchar() 返回值都可以表示为unsigned char

uintmax_t count_space = 0;
for (int c; (c = getchar()) != EOF; )
  if (isspace(c))
    ++count_space;

此代码可能会导致未定义的行为吗?

【问题讨论】:

  • 所有 ctype.h 函数都经过设计,以便它们可以处理可能是字符或 EOF 的输入。来自 C 的基本原理:“由于这些函数通常主要用作宏,因此它们的域仅限于可以用 unsigned char 表示的小的正整数,加上 EOF 的值。”
  • @Lundin isspace(CHAR_MIN) 在某些平台上未定义 (follow the link in the question or in the answer below)。

标签: c language-lawyer c11


【解决方案1】:

根据C11WG14 draft version N1570

§7.21.7.6/2 getchar 函数等效于带有参数 stdin 的 getc

§7.21.7.5/2getc函数等价于fgetc...

§7.21.7.1/2 [!=EOF case] ...fgetc 函数将该字符作为 unsigned char 转换为 int... [...] 中的文字是我的。

即,

  • isspace() 接受 getchar()
  • 所有getchar()!=EOF 值都可以表示为unsigned char
  • 这里没有未定义的行为。

如果您认为它太明显(“还有什么可能”),请再想一想。例如,the related caseisspace(CHAR_MIN) 可能是未定义的,即将字符传递给字符分类函数可能是未定义的行为!

如果UCHAR_MAX > INT_MAX,结果可能是实现定义的:

§6.3.1.3/3 否则,新类型是有符号的,值不能在其中表示;结果要么是实现定义的,要么引发实现定义的信号。

【讨论】:

  • 所以回到你关于CHAR_MIN的观点。在我看来,这始终是未定义的,因为负值永远不能表示为unsigned char,只能转换为它们。明显的例外情况是 CHAR_MIN 将是 EOF
  • @JensGustedt CHAR_MIN 在某些平台上可能为 0。
  • 是的,但有趣的情况是 CHAR_MIN 是否定的。或者另有说明,所有这些函数都只为正的char 值加上EOF 的例外定义。并且执行字符集的所有值都有非负值。
  • 你说“这是总是未定义” [强调我的]。我说:“CHAR_MIN 在某些平台上可能为 0。” 即,在此类平台上行为不是未定义的。
【解决方案2】:

getchar() 的返回值与fgetc() 的格式相同。 C11在7.21.7.1p2-3中定义了fgetc()的返回值:

  1. 如果未设置 stream 指向的输入流的文件结束指示符并且存在下一个字符,则fgetc 函数将获得该字符作为 unsigned char 转换为 int 并前进流的关联文件位置指示符(如果已定义)。

退货

  1. 如果设置了流的文件结束指示符,或者如果流处于文件结束位置,则设置流的文件结束指示符并且fgetc 函数返回@987654330 @。否则,fgetc 函数从流指向的输入流中返回下一个字符。如果发生读取错误,则设置流的错误指示符并且fgetc 函数返回EOF。 [289]

由于这是一个unsigned char 转换为intint几乎始终具有与无符号字符相同的值。

sizeof(int) == 1 的某些平台上可能不适合高值;然而,这些大多是 DSP 平台,因此几乎可以肯定这些平台不需要字符分类。


is* 函数经过精心定义,以便它们可以直接与*getc* 的返回值一起使用C11 7.4p1

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

即甚至将EOF 传递给is* 函数也是合法的。当然isanything(EOF) 将始终返回 0,因此要计算 连续 个空白字符,可以简单地使用类似的东西:

while (isspace(getchar())) space_count ++;

但是,有符号的字符值不正确,例如,如果将除 EOF 之外的负值传递给任何字符分类函数,则 MSVC C 调试库已知会中止

【讨论】:

  • 问题明确指出:“isspace() 如果 ... 或等于 EOF。”EOF 不是这里的问题。
  • 注意:问题中的代码计算空格数,直到返回 EOF。您的代码计算到第一个非空格字符。不一样。
  • @jfs note 这正是我将 continuous 这个词用斜体表示的原因。
  • 我的问题中的代码不计入 continuous 空格。这一切都很重要。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-25
  • 2023-03-14
  • 1970-01-01
  • 2018-08-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多