使用 isalnum 和带符号字符输入 - Visual C++

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

我有一个非常简单的程序,我使用

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
类型的参数。那么为什么这段代码会失败呢?我确信我在这里遗漏了一些微不足道的东西,但欢迎任何帮助。

c++
3个回答
4
投票

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]))

1
投票

问题是字符默认是带符号的,并且任何超过 0x7f 的值在传递给

isalnum
时都会被视为负数。进行这个简单的更改:

        if (isalnum((unsigned char)test[i])) {

微软的文档明确指出该参数是

int
,而不是
char
。我相信您对来自 isalnum
 标头的 
locale
不同版本感到困惑。我不知道为什么该函数不接受符号扩展负数,但怀疑它是基于标准中的措辞。


0
投票

这是一个解决方案,似乎有效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;
© www.soinside.com 2019 - 2024. All rights reserved.