我有一个非常简单的程序,我使用isalnum
函数来检查字符串是否包含字母数字字符。代码是:
#include "stdafx.h"
#include <iostream>
#include <string>
#include <locale>
using namespace std;
int _tmain(int argc, _TCHAR* argv[]) {
string test = "(…….";
for ( unsigned int i = 0; i < test.length(); i++) {
if (isalnum(test[i])) {
cout << "True: " << test[i] << " " << (int)test[i] << endl;
}
else {
cout << "False: " << isalnum(test[i]) << test[i] << " " << (int)test[i] << endl;
}
}
return 0;
}
我正在使用Visual Studio Desktop Edition 2013来获取此代码段。
问题:
1.当该程序在调试模式下运行时,程序失败并显示调试断言:&#34;表达式c> = -1&amp;&amp; c&lt; = 255&#34;
在ith
位置打印字符会产生负整数(-123)。将所有调用isalnum转换为接受unsigned char
作为输入会导致上述错误消失。
我查看了isalnum
的文档,并接受了char
类型的参数。那为什么这段代码片段失败了呢?我相信我在这里遗漏了一些小事,但欢迎任何帮助。
答案 0 :(得分:3)
isalnum
函数在<cctype>
(<ctype.h>
的C ++版本)中声明 - 这意味着您的源文件顶部确实应该有#include <cctype>
。您在没有#include
指令的情况下调用它是因为"stdafx.h"
或其中一个标准标题(可能是<locale>
)包含它 - 但它很糟糕想要依靠它。
isalnum
和朋友来自C. isalnum
函数采用int
类型的参数,该参数必须在unsigned char
或<的范围内/ em>等于EOF
(通常为-1
)。如果参数具有任何其他值,则行为未定义。
令人讨厌的是,这意味着如果普通的char
碰巧被签名,那么将char
值传递给isalnum
会导致未定义的行为,如果该值恰好为负且不等于{{ 1}}。普通EOF
的签名是实现定义的;它似乎是在大多数现代系统上签署的。
C ++添加了一个模板函数char
,它接受任何字符类型的参数和类型isalnum
的第二个参数。它的声明是:
std::locale
我非常确定此版本的template <class charT> bool isalnum (charT c, const locale& loc);
不会遇到与isalnum
中的问题相同的问题。您可以传递<cctype>
值,它将正确处理它。您也可以传递一个像char
这样的宽字符类型的参数。但它需要两个论点。由于您只将一个参数传递给wchar_t
,因此您不使用此版本;您正在使用isalnum()
中声明的isalnum
。
如果要使用此版本,可以将默认语言环境作为第二个参数传递:
<cctype>
或者,如果您确定只使用了较窄的字符(类型std::isalnum(test[i], std::locale())
),则可以将参数转换为char
:
unsigned char
答案 1 :(得分:1)
问题是默认情况下会对字符进行签名,并且传递给isalnum
时,任何超过0x7f的内容都会被视为负数。做出这个简单的改变:
if (isalnum((unsigned char)test[i])) {
Microsoft的documentation明确指出参数为int
,而不是char
。我相信你会对来自locale
标题的different version of isalnum
感到困惑。我不知道为什么函数不接受符号扩展的负数,但怀疑它是基于标准中的措辞。