“可表示”在C11中意味着什么?
根据C11 WG14草案版本N1570 :
头文件
声明了几个对字符分类和映射有用的函数。 在所有情况下,参数都是一个
int
,其值应表示为unsigned char
或者等于宏EOF
的值。 如果参数具有任何其他值,则行为未定义。
是不确定的行为?:
#include #include #include 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()
( char
为int
)? 换句话说,转换为int
后的unsigned char
是否可表示为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,如果INT_MAX >= UCHAR_MAX
,则isspace((unsigned char)c)
是可移植的,否则它是实现定义的。
在char被签名的假设下,这将是未定义的行为 ,否则它被很好地定义,因为CHAR_MIN
将具有值0
。 更容易看出以下内容的意图和含义:
其值应表示为无符号字符或等于宏EOF的值
如果我们从国际标准 – 编程语言的基本原理 – C中读到第7.4
节字符处理
由于这些函数通常主要用作宏,因此它们的域仅限于无符号字符中可表示的小正整数加上EOF的值 。 EOF传统上是-1,但可以是任何负整数,因此可以与任何有效的字符代码区分开。 因此,通过将参数用作小数组属性的索引,可以有效地实现这些宏。
所以有效值是:
- 正整数,可以放入unsigned char
-
EOF
是一些实现定义的负数
即使这是C99的基本原理,因为您所指的特定措辞不会从C99改为C11 ,因此理由仍然适用。
我们还可以找到为什么接口使用int作为参数而不是char ,从7.1.4
节使用库函数 ,它说:
所有库原型都是根据“加宽”类型指定的,以前声明为char的参数现在写为int。 这确保了可以在范围内使用或不使用原型来调用大多数库函数 ,从而保持与C89之前代码的向后兼容性 。 但请注意,由于printf和scanf等函数使用可变长度参数列表,因此必须在原型范围内调用它们。
类型中可表示什么意思?
重新制定,类型是基础位模式意味着什么的约定。 因此,值可以在类型中表示,如果该类型指定了某种意义的位模式。
转换(可能需要转换)是从值(用特定类型表示)到目标类型中表示的值(可能不同)的映射。
在给定的假设下( char
已签名), CHAR_MIN
肯定是否定的,并且您引用的文本没有留下解释的余地:
是的,它是未定义的行为,因为unsigned char
不能代表任何负数。
如果该假设不成立,那么您的程序将被很好地定义,因为CHAR_MIN
将为0
,这是unsigned char
的有效值。
因此,我们有一个案例,它是实现定义的程序是未定义的还是定义良好的。
另外,不能保证sizeof(int)>1
或INT_MAX >= CHAR_MAX
,因此int
可能无法表示unsigned char
可能的所有值。
由于转换被定义为保留值,因此有符号的char
总是可以转换为int
。
但如果它是否定的,那就不会改变将负值表示为unsigned char
不可能性。 (定义转换,因为始终定义从任何整数类型到任何unsigned
整数类型的转换,但缩小转换需要转换。)
揭示引言(对我来说)是§6.3.1.3/ 1:
如果值可以由新类型表示,则不会更改。
即,如果必须更改该值,则该值不能由新类型表示。
因此, unsigned
类型不能表示负值。
回答标题中的问题:“可表示”是指“可以表示”来自§6.3.1.3,与“对象表示”无关,来自§6.2.6.1。
回想起来似乎微不足道。 我可能会因为习惯将b'\xFF'
, 0xff
, 255
, -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)
是未定义的行为 。