将无符号的 int 与 std::string::size_type 进行比较是否安全



我将阅读Andrew Koenig和Barbara E. Moo的"加速C++"一书,我对第2章的主要示例有一些疑问。代码可以总结如下,并且使用 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++ 编译器将返回警告:

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

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

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

  • 使用unsigned intstd::string::size_type进行比较是否安全?在这种情况下,编译器不会返回警告,但我不确定它是否安全。
  • 为什么编译器没有对原始代码const int pad = 1发出警告。编译器是否自动将变量pad转换为unsigned int
  • 我也可以用string::size_type pad = 1;替换const int pad = 1;,但在我看来,变量pad的含义并没有真正与字符串大小相关联。不过,在这种情况下,这是避免在比较中使用不同类型的最佳方法吗?

从编译器的角度来看:

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

所以你的问题的答案:

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

比较有符号和无符号值是"危险的",因为当有符号值为负数时,您可能无法获得预期的结果(它很可能表现为非常大的无符号值,因此a > ba = -1b = 100时给出true。(使用const int有效是因为编译器知道该值没有更改,因此可以说"好吧,这个值始终是 1,所以它在这里工作正常")

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

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

[support.types]/6定义size_t

实现定义的无符号整数类型,其大小足以包含大小 以任何对象的字节为单位。

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

现在关于你的第二个问题:如果你使用const int something = 2,编译器会看到这个整数是 a) 永不负数和 b) 永不改变,因此将此变量与size_t进行比较总是安全的。在某些情况下,编译器可能会完全优化变量,并简单地用2替换所有出现的变量。

我想说的是,最好在您所在的任何地方使用size_type,因为它更冗长。

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

使用无符号 int 与 std::string::size_type 进行比较是否安全?在这种情况下,编译器不会返回警告,但我不确定它是否安全。

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

为什么编译器没有给出原始代码的警告 const int pad = 1。编译器是否会自动将变量垫转换为无符号 int?

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

我也可以替换 const int pad = 1; 通过 string::size_type pad = 1;,但在我看来,变量 pad 的含义并没有真正与字符串大小相关联。不过,在这种情况下,这是避免在比较中使用不同类型的最佳方法吗?

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

相关内容

  • 没有找到相关文章

最新更新