我有一个非常简单的程序,我使用
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. 当该程序在调试模式下运行时,程序失败并显示调试断言:“Expression c >= -1 && c <= 255"
在
ith
位置打印字符会产生负整数 (-123)。将所有调用转换为 isalnum 以接受 unsigned char
作为输入会导致上述错误消失。
我检查了
isalnum
的文档,它接受 char
类型的参数。那么为什么这段代码会失败呢?我确信我在这里遗漏了一些微不足道的东西,但欢迎任何帮助。
isalnum
函数在 <cctype>
(<ctype.h>
的 C++ 版本)中声明——这意味着您确实应该在源文件的顶部有 #include <cctype>
。您可以在没有 #include
指令的情况下调用它,因为 "stdafx.h"
或标准标头之一(可能是 <locale>
)包含它 - 但依赖它是一个坏主意。
isalnum
和朋友来自 C。 isalnum
函数采用 int
类型的参数,该参数必须在 unsigned char
或 等于 EOF
的范围内(通常为 -1
) )。如果参数有任何其他值,则行为未定义。
令人烦恼的是,这意味着如果普通的
char
碰巧被签名,则将 char
值传递给 isalnum
会导致未定义的行为(如果该值恰好为负且不等于 EOF
)。普通 char
的符号是实现定义的;它似乎在大多数现代系统上都有签名。
C++ 添加了一个 template 函数
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
:
std::isalnum(static_cast<unsigned char>(test[i]))
问题是字符默认是带符号的,并且任何超过 0x7f 的值在传递给
isalnum
时都会被视为负数。进行这个简单的更改:
if (isalnum((unsigned char)test[i])) {
微软的文档明确指出该参数是
int
,而不是char
。我相信您对来自 isalnum
标头的
locale
的不同版本感到困惑。我不知道为什么该函数不接受符号扩展负数,但怀疑它是基于标准中的措辞。
这是一个解决方案,似乎有效https://en.cppreference.com/w/cpp/string/byte/isalnum
我试图同意基思的观点。 尽管 static_cast 为 unsigned char 或将 locale() 作为第二个参数传递给 isalnum 函数,但在对 isalpha 或 isalnum 的函数/宏调用中总是以负整数结束,并破坏了程序执行
我的解决方案在我的上下文中工作,它构建一个仅允许字母数字和“ ”(空格字符)的字符串。
char, c;
string s {"somethings"};
if (c < 0)
s += ' ';
else
s += c;
return s;