将 unsigned int 与 std::string::size_type 进行比较是否安全

Is it safe to compare an unsigned int with a std::string::size_type

我正在阅读 Andrew Koenig 和 Barbara E. Moo 的书"Accelerated C++",我对第 2 章中的主要示例有一些疑问。代码可以总结如下,并且在没有 warning/error 与 g++:

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

但是,如果我将 const int pad = 1; 替换为 int pad = 1;,g++ 编译器将 return 发出警告:

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

如果我用 unsigned int pad = 1; 替换 const int pad = 1;,g++ 编译器将不会 return 警告。

我理解为什么 g++ return 警告,但我不确定以下三点:

如果您将 std::string 与默认分配器一起使用(这很可能),那么 size_type 实际上是 size_t.

[support.types]/6 定义 size_t

an implementation-defined unsigned integer type that is large enough to contain the size in bytes of any object.

所以在技术上不能保证它是 unsigned int,但我相信在大多数情况下它都是这样定义的。

现在关于你的第二个问题:如果你使用 const int something = 2,编译器会发现这个整数 a) 从不为负且 b) 从不改变,所以将这个变量与 [=12= 进行比较总是安全的].在某些情况下,编译器可能会完全优化变量并简单地用 2.

替换所有出现的变量

我会说最好在任何地方都使用 size_type,因为它更冗长。

比较有符号和无符号值是 "dangerous",因为当有符号值为负时,您可能得不到预期的结果(它很可能表现为一个非常大的无符号值,因此 a > ba = -1b = 100 时给出 true。(const int 的使用是有效的,因为编译器知道值没有改变,因此可以说 "well, this value is always 1, so it works fine here" )

只要您要比较的值在 unsigned int 范围内(在典型的机器上,略高于 40 亿)就可以了。

编译器警告的是无符号和有符号整数类型的比较。这是因为有符号整数可以是负数,意思是违反直觉的。这是因为有符号在比较之前被转换为无符号,这意味着负数会比较大于正数

Is it safe to use an unsigned int in order to compare with a std::string::size_type? The compiler does not return a warning in that case but I am not sure if it is safe.

是的,它们都是无符号的,语义符合预期。如果它们的范围不同,则将较窄的转换为较宽的类型。

Why is the compiler not giving a warning with the original code const int pad = 1. Is the compiler automatically converting the variable pad to an unsigned int?

这是因为编译器的构造方式。编译器在发出警告之前解析并在某种程度上优化代码。重要的一点是,在考虑此警告时,编译器现在知道有符号整数是 1,然后可以安全地与无符号整数进行比较。

I could also replace const int pad = 1; by string::size_type pad = 1;, but the meaning of the variable pad is not really linked to a string size in my opinion. Still, would this be the best approach in that case to avoid having different types in the comparison?

如果您不希望它保持不变,最好的解决方案可能是使其至少成为无符号整数类型。但是你应该知道,正常整数类型和大小之间没有保证的关系,例如 unsigned int 可能更窄、更宽或等于 size_tsize_type(后者也可能不同).

从编译器的角度来看:

  1. 比较有符号和无符号变量(非常量)是不安全
  2. 比较 2 个不同大小的未签名变量是安全的
  3. 如果编译器可以检查常量是否在有符号变量类型的允许范围内(例如,对于16 位有符号整数,使用 [0..32767] 范围内的常量是安全的。

所以你的问题的答案:

  1. 是的,比较 unsigned intstd::string::size_type 是安全的。
  2. 没有警告,因为编译器可以执行安全检查(编译时:))。
  3. 使用不同的 unsigned 类型进行比较,没有 问题。使用 unsinged int.