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

时间:2015-02-18 16:47:00

标签: c++

我有一个非常简单的程序,我使用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类型的参数。那为什么这段代码片段失败了呢?我相信我在这里遗漏了一些小事,但欢迎任何帮助。

2 个答案:

答案 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感到困惑。我不知道为什么函数不接受符号扩展的负数,但怀疑它是基于标准中的措辞。