C++ 比较无符号int和std::string::size\u类型是否安全

C++ 比较无符号int和std::string::size\u类型是否安全,c++,unsigned,stdstring,C++,Unsigned,Stdstring,我正在阅读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 =

我正在阅读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
无符号整数pad=1,则g++编译器不会返回警告

我理解g++返回警告的原因,但我不确定以下三点:


  • 使用
    无符号int
    std::string::size\u类型进行比较是否安全?在这种情况下,编译器不会返回警告,但我不确定它是否安全
  • 为什么编译器没有用原始代码
    const int pad=1
    发出警告。编译器是否自动将变量
    pad
    转换为
    无符号int
  • 我还可以替换
    const int pad=1
    string::size\u type pad=1
    ,但在我看来,变量
    pad
    的含义实际上与字符串大小无关。不过,在这种情况下,这是避免在比较中使用不同类型的最佳方法吗

如果将
std::string
与默认分配器一起使用(很可能),那么
size\u type
实际上是
size\u t

[support.types]/6定义了
大小

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

因此,从技术上讲,它不能保证是一个
无符号int
,但我相信它在大多数情况下都是这样定义的

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


我想说的是,最好在任何地方都使用
size\u type
,因为它更详细。

比较有符号值和无符号值是“危险的”,因为当有符号值为负值时,您可能得不到预期的结果(它可能表现为一个非常大的无符号值,因此
a>b
a=-1
b=100
时给出
true
(使用
const int
有效,因为编译器知道值没有变化,因此可以说“好吧,这个值总是1,所以在这里工作正常”)


只要要比较的值符合
unsigned int
(在典型机器上,略高于40亿)很好。

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

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

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

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

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

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


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

从编译器的角度来看:

  • 比较有符号变量和无符号变量(非常量)是不安全的
  • 比较两个不同大小的非单变量是安全的
  • 如果编译器可以检查无符号变量是否在有符号变量类型的允许范围内(例如,对于16位有符号整数,使用[0..32767]范围内的常数是安全的),则可以将无符号变量与单个常量进行比较
  • 因此,您的问题的答案如下:


  • 是的,比较
    无符号int
    std::string::size\u type
    是安全的
  • 没有警告,因为编译器可以执行安全检查(编译时:)
  • 比较时使用不同的无符号类型没有问题。请使用
    无符号int

  • 从msdn:
    basic\u string::size\u type
    =>
    typedef typename分配器\u type::size\u type size\u type;
    =>可以表示字符串中元素和索引数量的无符号整数类型。().因此,使用非单精度int可能是一个好方法approach@Fefux我不相信微软是C/C++标准的权威来源。这些年来,他们对这些标准有足够的“创造性”解释…
    if((int)C==pad+1)
    std::string::size\u type
    不是
    warning: comparison between signed and unsigned integer expressions [-Werror=sign-compare]
        if (c == 1 + pad)