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

问题描述 投票:6回答:3

根据C11 WG14 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 >= UCHAR_MAX,否则它是实现定义的。

c language-lawyer c11
3个回答
4
投票

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

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

如果我们从7.4读到部分Rationale for International Standard—Programming Languages—C字符处理<ctype.h>(强调我的前进):

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

所以有效值是:

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

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

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

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


10
投票

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

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

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


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

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

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


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

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


1
投票

(对我而言)揭示的引用是§6.3.1.3/ 1:

如果值可以由新类型表示,则不会更改。

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

因此,unsigned类型不能代表负值。

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

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

>>> (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))是一种未定义的行为。

© www.soinside.com 2019 - 2024. All rights reserved.