"可表示"在C11中意味着什么?

jfs*_*jfs 6 c language-lawyer c11

根据C11 WG14草案版本N1570:

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

是不确定的行为?:

#include <ctype.h>
#include <limits.h>
#include <stdlib.h>

int main(void) {
  char c = CHAR_MIN; /* let assume that char is signed and CHAR_MIN < 0 */
  return isspace(c) ? EXIT_FAILURE : EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)

标准是否允许传递charisspace()(charint)?换句话说,char转换后可以int 表示unsigned char


以下是wiktionary定义"可表示"的方式:

能够代表.

char能够被表示为unsigned char是的.§6.2.6.1/ 4:

存储在任何其他对象类型的非位字段对象中的值由n × CHAR_BIT位组成,其中n是该类型对象的大小(以字节为单位).可以将该值复制到unsigned char [ n ] 类型的对象中 (例如,通过memcpy); 生成的字节集称为值的对象表示.

sizeof(char) == 1因此,它的对象表示unsigned char[1]即,char能够表示为unsigned char.我哪里错了?

具体的例子,我可以表示[-2, -1, 0, 1][0, 1, 2, 3].如果我不能那么?


相关:根据§6.3.1.3 isspace((unsigned char)c)是可移植的,INT_MAX >= UCHAR_MAX否则它是实现定义的.

Ded*_*tor 10

一个类型中可表示什么意思?

重新制定,类型是基础位模式意味着什么的约定.因此,值可以在类型中表示,如果该类型指定了某种意义的位模式.

转换(可能需要转换)是从值(用特定类型表示)到目标类型中表示的值(可能不同)的映射.


在给定的假设(char已签名)下,CHAR_MIN肯定是否定的,并且您引用的文本没有留下解释的余地​​:
是的,它是未定义的行为,因为unsigned char不能代表任何负数.

如果这个假设不成立,你的程序将被明确定义,因为CHAR_MIN它将是0一个有效的值unsigned char.

因此,我们有一个案例,它是实现定义的程序是未定义的还是定义良好的.


顺便说一句,没有任何保证sizeof(int)>1INT_MAX >= CHAR_MAX,因此int可能无法代表所有值可能unsigned char.

由于转换被定义为保留值,因此char可以始终将签名转换为int.
但如果它是否定的,那就不会改变代表负值的不可能性unsigned char.(定义转换,因为unsigned始终定义从任何整数类型到任何整数类型的转换,但缩小转换需要转换.)


Sha*_*our 4

假设char符号,那么这将是未定义的行为,否则它是明确定义的,因为CHAR_MIN将具有值0。更容易看出其意图和含义:

\n\n
\n

其值应表示为无符号字符或应等于宏 EOF 的值

\n
\n\n

如果我们阅读《Rationale for International Standard\xe2\x80\x94Programming Languages\xe2\x80\x94C》中的7.4 字符处理 <ctype.h>部分,其中表示(重点是我的未来):

\n\n
\n

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

\n
\n\n

所以有效值为:

\n\n
    \n
  1. 可以放入 unsigned char 的正整数
  2. \n
  3. EOF这是一些实现定义的负数
  4. \n
\n\n

尽管这是 C99 的基本原理,因为您所指的特定措辞不会从C99更改为C11,因此该基本原理仍然适合。

\n\n

我们还可以从部分中找到为什么该接口使用int作为参数而不是char7.1.4 ,它说:

\n\n
\n

所有库原型均根据 \xe2\x80\x9cwidened\xe2\x80\x9d 类型指定\n 以前声明为 char 的参数现在写为 int。这 确保了大多数库函数都可以在范围内使用或不使用原型的情况下进行调用,从而保持向后兼容性与 C89 之前的代码的但请注意,由于 printf 和 scanf 等函数使用可变长度参数列表,因此必须在原型范围内调用它们。

\n
\n

  • @JFSebastian 似乎可能会避免与“EOF”重叠,这会很糟糕。它还提供了一个清晰的界面。 (2认同)
  • 我可能会误解“clear”这个词,但这是一个糟糕的 API 设计,将字符传递给字符分类函数可能会导致未定义的行为。 (2认同)