2017-03-27 40 views
4

我要通過Andrew Koenig和Barbara E. Moo編寫的「Accelerated C++」一書,我對第2章中的主要示例有一些疑問該代碼可以被總結如下,並且在不警告/錯誤被編譯具有克++:安全地比較unsigned int和std :: string :: size_type

#include <string> 
using std::string; 

int main() 
{ 
    const string greeting = "Hello, world!"; 
    // OK 
    const int pad = 1; 
    // KO 
    // int pad = 1; 
    // OK 
    // unsigned int pad = 1; 
    const string::size_type cols = greeting.size() + 2 + pad * 2; 
    string::size_type c = 0; 
    if (c == 1 + pad) 
    {;} 

    return 0; 
} 

然而,如果我通過int pad = 1;取代const int pad = 1;,g ++編譯器將返回一個警告:

warning: comparison between signed and unsigned integer expressions [-Werror=sign-compare] 
    if (c == 1 + pad) 

如果我用替換,g ++編譯器不會返回警告。

我明白了爲什麼G ++返回警告,但我不知道這三個以下幾點:

  • 是安全的,以便與std::string::size_type比較使用unsigned int?編譯器在這種情況下不會返回警告,但我不確定它是否安全。
  • 爲什麼編譯器沒有給出原始代碼const int pad = 1的警告。編譯器是否自動將變量pad轉換爲unsigned int
  • 我也可以用string::size_type pad = 1;替代const int pad = 1;,但是在我看來,變量pad的含義並沒有真正與鏈接大小相關聯。不過,在這種情況下,這是否是避免在比較中使用不同類型的最佳方法?
+0

從msdn:'basic_string :: size_type' =>'typedef typename allocator_type :: size_type size_type;'=>無符號整數類型,可以表示字符串中元素和索引的數量。 (https://msdn.microsoft.com/library/5ddehwe8.aspx)。所以使用unsinged int可能是一個好方法 – Fefux

+0

@Fefux我不相信微軟作爲C/C++標準的授權源。他們對這些年的標準有足夠的「創造性」解釋...... – skyking

+0

'if((int)c == pad + 1)' – i486

回答

2

但從編譯點:

  1. 這是不安全比較簽署並unsinged變量(非常量)。
  2. 它是安全來比較2個不同大小的無符號變量。
  3. 它是安全如果編譯器可以檢查該常量是否在簽名變量類型的允許範圍內(例如,對於16位有符號整數,則可以安全使用範圍[0..32767]的常數)。

因此,問題的答案:

  1. 是的,它是安全的比較unsigned intstd::string::size_type
  2. 沒有警告,因爲編譯器可以執行安全檢查(編譯時:))。
  3. 還有問題使用不同無符號類型相比較。使用unsinged int
1

如果使用std::string使用默認分配器(這是有可能的),那麼size_type實際上是size_t

[support.types]/6定義size_t

實現定義無符號整型,其足夠大以包含任何對象的字節大小 。

因此它在技術上並不保證是unsigned int,但我相信它在大多數情況下都是這樣定義的。

現在關於你的第二個問題:如果你使用const int something = 2,編譯器發現這個整數是a)從不是負數,b)永遠不會改變,因此總是可以安全地比較這個變量和size_t。在某些情況下,編譯器可能會完全優化變量,並簡單地將其全部替換爲2

我會說,最好是在任何地方使用size_type,因爲它比較冗長。

+1

'std :: string :: size_type'不能保證是'size_t '。 –

+1

@MatsPetersson,true,但如果你使用默認的分配器,它似乎是OP的情況下它'std :: size_t'。 – SingerOfTheFall

+0

不一定。有人可能會認爲在64位計算機上將長度存儲爲32位值具有某些特定優勢。不,這不是常見的做法,但仍然有可能。 –

1

比較有符號和無符號值是在這個意義上「危險」,當符號值是負數,你期待什麼(很可能表現爲一個非常大的無符號值,從而a > b給您可能無法獲得truea = -1b = 100。(使用const int是因爲編譯器知道該值沒有變化,因此可以說「好吧,這個值總是1,所以它在這裏工作正常」)

只要你想比較的值符合在unsigned int(在典型的機器上,有點超過40億)是好的。

1

編譯器警告的是無符號和有符號整數類型的比較。這是因爲有符號整數可能是負數,意思是違反直覺的。這是因爲在比較之前將有符號轉換爲無符號,這意味着負數將比較大於正數

爲了與std :: string :: size_type進行比較,使用unsigned int是否安全?編譯器在這種情況下不會返回警告,但我不確定它是否安全。

是的,他們都是無符號的,然後語義是預期的。如果它們的範圍不同,則較窄的範圍轉換爲更寬的範圍。

爲什麼編譯器沒有給出原始代碼的警告const int pad = 1。編譯器是否自動將變量pad轉換爲unsigned int?

這是因爲如何構造編譯器。編譯器解析並在發出警告之前在一定程度上優化代碼。重要的一點是,在考慮這個警告的時候,編譯器會發現有符號整數是1,然後與無符號整數比較是安全的。

我也可以替換const int pad = 1;通過string :: size_type pad = 1 ;,但在我看來,變量pad的含義並不真正鏈接到字符串大小。不過,在這種情況下,這是否是避免在比較中使用不同類型的最佳方法?

如果你不希望它是常量,最好的解決方案可能是使它至少是一個無符號整數類型。但是,您應該知道,在正常整數類型和大小之間沒有保證關係,例如unsigned int可能較窄,較寬或等於size_tsize_type(後者也可能不同)。