簡體   English   中英

我的 For 循環有什么問題? 我收到警告:有符號和無符號整數表達式之間的比較 [-Wsign-compare]

[英]What is wrong with my For loops? i get warnings: comparison between signed and unsigned integer expressions [-Wsign-compare]

#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;
}

為什么-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)

autostd::vector<int>::iterator的簡寫。 迭代器適用於任何類型的容器,而索引將您限制為 C 數組、 dequevector

這是因為來自 vector 類的 .size() 函數不是 int 類型而是 vector::size_type 類型

使用那個或auto i = 0u並且消息應該消失。

我通常是這樣解決的:

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

我使用 C 風格的static_cast<int>()因為它比 C++ static_cast<int>()更短、更易讀,並且完成了同樣的事情。

這里存在溢出的可能性,但前提是您的向量大小大於最大的int ,通常為 2147483647。我一生中從未有過這么大的向量。 如果使用更大向量的可能性size_type那么建議size_type的答案之一會更合適。

我不擔心在循環中重復調用size() ,因為它可能是對不引入開銷的成員變量的內聯訪問。

您收到此警告是因為 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++ 語義,即使在當時也是錯誤的選擇)。

int默認是有符號的——它相當於寫了signed int 您收到警告的原因是size()返回一個vector::size_type ,它很可能是無符號的。

這具有潛在危險,因為signed intunsigned int持有不同范圍的值。 signed int可以保存–21474836482147483647之間的值,而unsigned int可以保存04294967295之間的值(假設int是 32 位)。

您的變量i是一個整數,而返回Allocator::size_type的 vector 的size成員函數很可能返回一個size_t ,它幾乎總是作為某種大小的無符號整數實現。

使您的int isize_type i
std::vector::size()將返回size_type ,它是一個unsigned int因為 size 不能為 -ve。
警告顯然是因為您將有符號整數與無符號整數進行比較。

在這么多答案之后回答,但沒有人注意到循環結束..所以,這是我的完整答案:

  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 這將使以后更容易更改容器類型(當然,如果您不需要數字的確切位置)。 所以,我會這樣寫:

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

為我聲明 'size_t i' 效果很好。

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

一些答案建議使用auto ,但這不起作用,因為int是從整數文字推導出的默認類型。 您必須明確指定cstddef標頭中定義的類型std::size_t

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

在 c++23 中添加了整型文字zu ,其動機確實是為了允許推導出正確的類型。

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

但不幸的是,尚無編譯器支持此功能。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM