2017-03-27 37 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(后者也可能不同)。