【问题标题】:What does "representable" mean in C11?C11中的“可代表”是什么意思?
【发布时间】:2014-11-04 18:36:50
【问题描述】:

根据C11WG14 draft version N1570

标题<ctype.h> 声明了几个对分类有用的函数 和映射字符。在所有情况下,参数都是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;
}

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


这是wiktionary defines "representable"

能够被代表。

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 &gt;= UCHAR_MAX 否则它是实现定义的。

【问题讨论】:

  • 我会说它是否是未定义的行为是未指定的——char 可以是无符号的,所以CHAR_MIN 可以是0。对于有符号字符,-1 是一个有效值,但它不能表示为 unsigned char(它不在此类型的可表示值范围内)。
  • @dyp:它是未指定的还是实现定义的?假设charsigned(很常见)。我会更新问题
  • @dyp: signed-ness of plain char 必须记录在案,因此无论是未定义行为还是明确定义,它都只是实现定义的。
  • @Deduplicator 你是对的。它要么是普通的 UB,要么是实现定义的,无论它是否是 UB。
  • @dyp:在评论中回答我的问题:草案在 6.2.5/15 中说 “实现应将 char 定义为具有与签名相同的范围、表示和行为char 或 unsigned char. 45)" 即,它不仅仅是未指定的,它是实现定义的(实现记录选择)。

标签: c language-lawyer c11


【解决方案1】:

类型中的可表示是什么意思?

重新表述,类型是底层位模式含义的约定。因此,如果该类型赋予某种位模式该含义,则该值可以在类型中表示。

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


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

如果该假设不成立,您的程序将是明确定义的,因为 CHAR_MIN 将是 0unsigned char 的有效值。

因此,我们有这样一种情况,即程序是未定义的还是定义良好的,都是由实现定义的。


顺便说一句,不能保证sizeof(int)&gt;1INT_MAX &gt;= CHAR_MAX,所以int 可能无法代表unsigned char 的所有可能值。

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

【讨论】:

  • sizeof(int)==1 确实很有趣; DS9K 实现可能有一个无符号字符 char 类型,其值似乎大于 int 可以表示的值。
  • DS9K 的另一个崇拜者,我明白了。他们最终应该会交付我的。
  • 您能否详细说明“您引用的文字没有解释的余地​​”部分??问题是“可代表”这个词是什么意思。我可以将所有char 值表示为unsigned char(该公式可能取决于实现,但对于所有实现它存在)。该标准可能使用不同的含义。你能描述一下那个意思吗?想象一下它是english.SE,但对于程序员来说。
  • @J.F.Sebastian:变化很大。现在好点了吗?
  • @Deduplicator:常见。你有没有说过char 小于CHAR_MAX + 1 意味着char 类型的任何值都小于CHAR_MAX + 1(数学上)?通常用相同的名称来指代集合和集合的成员。我已经使用直接引用 §6.2.6.1/4 澄清了避免任何歧义的含义。
【解决方案2】:

charsigned 的假设下,这将是 undefined behavior,否则它是明确定义的,因为 CHAR_MIN 将具有值 0。更容易看出以下意图和含义:

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

如果我们从Rationale for International Standard—Programming Languages—C 中阅读7.4 字符处理部分,其中说(强调我的前进):

由于这些函数通常主要用作宏,它们的域 仅限于可表示的小正整数 unsigned char,加上EOF的值。 EOF 传统上为 -1,但可能 是任何负整数,因此可与任何有效的 字符代码。因此,这些宏可以通过以下方式有效地实现 使用参数作为一个小属性数组的索引。

所以有效值是:

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

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

我们还可以从7.1.4 部分中找到为什么接口使用 int 作为参数而不是 char库函数的使用 ,它说:

所有库原型都是根据“扩展”类型指定的 以前声明为 char 的参数现在写为 int。这 确保大多数库函数都可以使用或不使用 范围内的原型,从而保持向后兼容性 C89 之前的代码。但是请注意,由于 printf 和 scanf 使用可变长度参数列表,它们必须在 原型的范围。

【讨论】:

  • @JFSebastian 这没有什么问题,演员表会将带符号的字符(假设它已签名,否则它什么都不做)转换为无符号的范围char 通过6.3.1.3 p 2 中的规则。
  • 我知道,在我的问题和answer 中都引用了§6.3.1.3。我的意思是为什么 (unsigned char) 没有在 isspace() 内部使用以避免未定义的行为。
  • @J.F.Sebastian 似乎可能会避免与EOF 重叠,这会很糟糕。它还提供了一个清晰的界面。
  • UB 为 char 值传递为 int不是一个清晰的界面。恰恰相反。它可能会起作用(它适用于我系统上的 gcc、clang),它可能会使您的程序崩溃或向火星发送一封信。根据“接口”都是有效的。我会理解关于不妥协时间性能的论点,例如,如果有更安全的选择,(c != EOF) &amp;&amp; (_uctype[(unsigned char)c] &amp; _SPACE) 可能比(_ctype + 1)[c] &amp; _S 慢。
  • 我可能误解了“clear”这个词,但这是一个糟糕的 API 设计,将字符传递给字符分类函数可能会导致未定义的行为。
【解决方案3】:

启示录(对我来说)是§6.3.1.3/1:

如果值可以用新类型表示,则不变。

即,如果必须更改值,则该值不能由新类型表示。

因此unsigned 类型不能表示负值。

回答标题中的问题:“可表示”是指 §6.3.1.3 中的“可以表示”,与 §6.2.6.1 中的“对象表示”无关。

回想起来似乎微不足道。我可能对在 Python 中将b'\xFF'0xff255-1 视为同一个字节的习惯感到困惑:

>>> (255).to_bytes(1, 'big')
b'\xff'
>>> int.from_bytes(b'\xFF', 'big')
255
>>> 255 == 0xff
True
>>> (-1).to_bytes(1, 'big', signed=True)
b'\xff'

并且不相信将字符传递给字符分类函数是一种未定义的行为,例如isspace(CHAR_MIN)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-08-18
    • 1970-01-01
    • 1970-01-01
    • 2011-08-12
    • 2017-06-11
    • 2018-03-05
    • 2023-03-27
    相关资源
    最近更新 更多