isdigit(c) - 字符或整数类型?
isdigit(c) - a char or int type?
我编写了以下代码来测试给定的输入是否为数字。
#include<iostream>
#include<ctype.h>
#include<stdio.h>
using namespace std;
main()
{
char c;
cout<<"Please enter a digit: ";
cin>>c;
if(isdigit(c)) //int isdigit(int c) or char isdigit(char c)
{
cout<<"You entered a digit"<<endl;
}
else
{
cout<<"You entered a non-digit value"<<endl;
}
}
我的问题是:输入变量类型应该是什么?char 还是 int?
不幸的是,情况比其他答案要复杂一些。
首先:代码的第一部分是正确的(不考虑多字节编码(;如果你想用cin
读取单个char
,你必须使用带有>>
运算符的char
变量。
现在,关于isdigit
:为什么需要int
而不是char
?
这一切都来自 C;isdigit
和它的同伴生来就是为了与getchar()
这样的函数一起使用,这些函数从流中读取一个字符并返回一个int
。这样做反过来是为了提供字符和错误代码:getchar()
可以通过其返回代码返回EOF
(定义为某个实现定义的负常量(,以表示输入流已结束。
所以,基本思想是:负=错误代码;正=实际字符代码。
不幸的是,这带来了与"常规"char
的互操作性问题。
简短的题外话:char
最终只是一个范围非常小的积分类型,但是一个特别愚蠢的类型。在大多数情况下 - 使用字节或字符代码时 - 您希望默认情况下unsigned
它;OTOH,出于与其他积分类型(int
、short
、long
、...(的一致性原因,您可能会说正确的做法是应该signed
普通char
。标准选择了最愚蠢的方式:普通char
要么是signed
要么是unsigned
,这取决于编译器的实现者决定什么1.
因此,你必须为char
signed
或unsigned
做好准备;在大多数实现中,它是默认signed
的,这给上面的getchar()
安排带来了问题。
如果char
用于读取字节并且signed
则意味着所有设置了高位的字节(AKA 字节,使用unsigned
8 位类型读取将为>127(变为负值。这显然与使用负值进行EOF
getchar()
不兼容 - 实际的"负"字符和EOF
之间可能存在重叠。
因此,当 C 函数谈论在变量中接收/提供字符时int
契约总是假定该字符是已强制转换为unsigned char
的char
(因此它始终是正值,负值溢出到其范围的上半部分(,然后放入int
中。这让我们回到了isdigit
函数,它连同其配套函数,也有这样的契约:
标头
<ctype.h>
声明了几个可用于分类和映射字符的函数。在所有情况下,参数都是一个int
,其值应表示为unsigned char
或等于宏EOF
的值。如果参数具有任何其他值,则行为未定义。
(C99, §7.4, ¶1(
所以,长话短说:你的if
至少应该是:
if(isdigit((unsigned char)c))
问题不仅仅是理论上的问题:一些广泛使用的 C 库实现直接使用提供的值作为查找表的索引,因此负值将读入未分配的内存并隔离程序。
此外,您没有考虑到流可能被关闭的事实,因此>>
返回而不触及您的变量(它将处于未初始化的值(;要考虑到这一点,您应该在处理c
之前检查流是否仍处于有效状态。
- 当然,这有点不公平;正如@Pete Becker在下面的评论中指出的那样,这并不是说他们都是白痴,而只是该标准主要试图与现有实现兼容,这些实现可能在未签名和已签名
char
之间平均分配。这种分裂的痕迹可以在大多数现代编译器中找到,它们通常可以通过命令行选项(gcc/clang 的-fsigned-char
/-funsigned-char
,/J
VC++ 中的(来更改char
的符号。
如果你想读取一个字符并检查它是否是一个数字,那么它应该是字符。
如果将其设置为 int,则将读取多个字符,并且 isDigit 的结果将始终为 true。
- 整数类型应该显式转换(例如"int"到"无符号")还是只会增加混乱?
- 涉及旧式枚举和整数类型的重载解析
- 将字符串转换为整数类型T,检查是否存在溢出
- 整数文本太大,无法用任何整数类型表示--C++
- isdigit(c) - 字符或整数类型?
- 为什么对小于 4 个字节的整数类型的位操作会发生意外行为?
- C++模板专用化 - 将其他整数类型委托给uint64_t
- 何时应使用 C++ 固定宽度整数类型,它们如何影响性能?
- 根据浮点数选择最小整数类型
- 为什么 QVariant 将字符类型视为整数类型
- 我们可以在整数类型的双指针中分配2D整数数组的地址吗?怎么可能
- 默认情况下,决定整数类型是唱歌或无符号的类型
- 是否可以根据类型是整数类型还是浮点类型重载模板函数
- 使用固定整数类型的安全性
- 如何使用条件来检查类型名 T 是否是 C++ 中浮点类型的整数类型
- C++文本整数类型
- 哪种整数类型可以安全且便携式用于始终保持指针值
- 检测整数类型变量上的空白输入
- 为什么对Chrono :: Nanseconds的表示类型是签名的整数类型
- 如何处理警告:从较小的整数类型int转换为int*