现在的位置: 首页 > 综合 > 正文

避免将unsigned int和int放在布尔表达式中作比较

2013年01月22日 ⁄ 综合 ⁄ 共 1069字 ⁄ 字号 评论关闭

这个标题不够犀利,不少人看到第一反应肯定是——“这我知道啊”。但是很多人肯定写过如下的代码:

#include<iostream>
#include<string>
#include<cstring>
using namespace std;
int main()
{
    string s = "abcde";
    for(int i = 0; i < s.size(); ++i) {
        s[i] = toupper(s[i]);
    }
    cout<<s<<endl;
}

这个例子是将所有的小写字母变成大写字母,很正常。但是这种编程习惯有个隐藏的风险,再来看下面这段代码,这段代码的作用是,遍历容器v,然后每次将长度不大于range的字符串打印出来。range会逐渐减小。你觉得输出的结果是什么?

#include<cstring>
#include<iostream>
#include<string>
#include<vector>
using namespace std;
int main()
{
    vector<string> v;
    v.push_back("abc");
    v.push_back("ab");
    v.push_back("a");
    v.push_back("ab");
    v.push_back("abc");
    int range = 3;
    for(int i = 0; i < v.size(); ++i, --range) {
        if(v[i].size() <= range) {
            cout<<v[i]<<endl;
        }
    }
}

正常而言,我们期望它的输出如下:

abc
ab
a

但实际输出是:

abc
ab
a
abc

是不是有人觉得自己不会写出这样的代码,即便在其它地方也不会出现非这样写不可的情况。但事实是,你写了都不知道……我今天做leetcode的“text justification”用了很久才发现布尔表达式里面计算出了非常奇怪的结果,浪费了很多时间。

上面代码的问题在于用一个无符号unsigned值与一个有符号的int作比较,当range变为-1的时候,在表达式v[i].size() <= range中,它会被转换成一个无符号的数,因此会变成一个很大的正数,程序的输出就和原来期望不复合了。

当然也不是说永远不能让无符号和有符号的数比较,但是你在这么写的时候,一定要知道自己在做什么,并且知道这样做是没有问题的。如果用Visual Studio,我印象中其对于这种比较是会出警告的,但是很多编译器就不会警告。问题是即便我用Visual Studio,也会自动忽略那段编译警告,Xcode就压根没有警告……

C++用得比较多,但是我越用越觉得自己好像就没怎么掌握这门语言哭

抱歉!评论已关闭.