我的For循环有什么问题?我收到警告:有符号和无符号整数表达式之间的比较[-Wsign-compare]

时间:2011-11-02 17:49:25

标签: c++

#include <iostream>
#include <string>
#include <vector>
#include <sstream>


using namespace std;

int main() {

    vector<double> vector_double;
    vector<string> vector_string;
    ...


    while (cin >> sample_string)
        {
            ...
        }

    for(int i = 0; i <= vector_string.size(); i++)
        {
            ....
        }

    for (int i = 0; i < vector_double.size(); i++)
        ....


    return 0;
}

11 个答案:

答案 0 :(得分:15)

  

为什么-Wsign-compare会出现警告?

作为警告的名称及其文本暗示,问题在于您要比较有符号整数和无符号整数。通常认为这是一次意外。

为了避免此警告,您只需确保<(或任何其他比较运算符)的两个操作数都已签名或两者都未签名。

  

我怎么能做得更好?

编写for循环的惯用方法是在第一个语句中初始化计数器和限制

for (std::size_t i = 0, max = vec.size(); i != max; ++i)

这样可以在每次迭代时保存重新计算size()

您也可以(也可能应该)使用迭代器而不是索引:

for (auto it = vec.begin(), end = vec.end(); it != end; ++it)

auto这是std::vector<int>::iterator的简写。迭代器适用于任何类型的容器,而索引将您限制为C阵列,dequevector

答案 1 :(得分:7)

这是因为vector类中的.size()函数不是int类型,而是vector :: size_type

使用或auto i = 0u,消息应该消失。

答案 2 :(得分:3)

int默认签名 - 相当于撰写signed int。您收到警告的原因是因为size()返回的vector::size_type很可能是未签名的。{/ p>

由于signed intunsigned int拥有不同的值范围,因此存在潜在危险。 signed int可以保存–21474836482147483647之间的值,而unsigned int可以保存04294967295之间的值(假设int是{{1}} 32位)。

答案 3 :(得分:2)

您的变量i是一个整数,而返回size的向量的Allocator::size_type成员函数最有可能返回size_t,这几乎总是实现为一些大小的unsigned int。

答案 4 :(得分:2)

int i设为size_type i std::vector::size()将返回size_type unsigned int,因为大小不能为-ve 警告显然是因为您正在将有符号整数与无符号整数进行比较。

答案 5 :(得分:2)

经过这么多答案后回答,但没有人注意到循环结束..所以,这是我的完整答案:

  1. 要删除警告,请将i的类型更改为unsignedauto(对于C ++ 11)或std::vector< your_type >::size_type
  2. 如果您使用此for作为索引,则i循环会出现段错误 - 您必须从0循环到size-1。所以,把它改成为
    for( std::vector< your_type >::size_type i = 0; i < vector_xxx.size(); ++i )
    (请注意<,而不是<=;我建议不要将<=.begin() - 1一起使用,因为您可以使用0大小的向量而有问题:))。
  3. 为了使这更通用,当您使用容器并且正在迭代它时,您可以使用iterator。这将使容器类型的未来更容易更改(当然,如果您不需要确切的位置作为数字)。所以,我会这样写:

  4. for( std::vector< your_type >::iterator iter = vector_XXX.begin(); 
         iter != vector_XXX.end(); 
         ++iter )
    {
        //..
    }
    

答案 6 :(得分:2)

您收到此警告是因为C ++中容器的大小是无符号类型,并且混合有符号/无符号类型是危险的。

我通常做的是

for (int i=0,n=v.size(); i<n; i++)
    ....

在我看来,这是使用索引的最佳方式,因为对索引使用无符号类型(或容器的大小)是一个逻辑错误。

仅当您关心位表示以及何时要在溢出时使用模/(2 ** n)行为时,才应使用无符号类型。仅仅因为值永远不是负数而使用无符号类型是无意义的。

对大小或索引使用无符号类型的典型错误是例如

// Draw all lines between adjacent points
for (size_t i=0; i<pts.size()-1; i++)
    drawLine(pts[i], pts[i+1]);

当点数组为空时,上面的代码是UB,因为在C ++中0u-1是一个巨大的正数。

C ++使用无符号类型表示容器大小的原因是因为选择它是16位计算机的历史遗产(IMO给出了带有无符号类型的C ++语义,即使在那时它也是错误的选择)。

答案 7 :(得分:2)

我通常会这样解决:

for(int i = 0; i <= (int)vector_string.size(); i++)

我使用C风格的强制转换,因为它比C ++ static_cast<int>()更短,更易读,并且完成同样的事情。

这里有可能出现溢出,但前提是你的矢量大小大于最大int,通常是2147483647.我生命中从来没有过大的矢量。如果甚至有可能使用更大的向量,那么建议size_type的答案之一会更合适。

我不担心在循环中反复调用size(),因为它可能是对成员变量的内联访问,不会引入任何开销。

答案 8 :(得分:1)

声明'size_t i'对我来说运作良好。

答案 9 :(得分:0)

std::cout << -1U << std::endl;
std::cout << (unsigned)-1 << std::endl;
4294967295

std::cout << 1 << std::endl;
std::cout << (signed)1 << std::endl;
1

std::cout << (unsigned short)-1 << std::endl;
65535

std::cout << (signed)-1U << std::endl;
std::cout << (signed)4294967295 << std::endl;
-1

取消索引变量的签名

unsigned int index;
index < vecArray.size() // size() would never be negative

答案 10 :(得分:0)

有些答案建议使用auto,但由于int是从整数文字推导出的默认类型,因此无法使用。在之前,您必须明确指定cstddef标头中定义的类型std::size_t

for(std::size_t i = 0; i <= vector_string.size(); i++)
{
    ....
}

在c ++ 23中,添加了整数zumotivation的确可以推断出正确的类型。

for(auto i = 0zu; i <= vector_string.size(); i++)
{
    ....
}

但不幸的是,尚无compiler support此功能。