【问题标题】:Comparison size_t variable with -1 (maximum size value) in c++ codec++ 代码中的 size_t 变量与 -1(最大大小值)的比较
【发布时间】:2014-08-02 10:43:54
【问题描述】:

我正在重构一个库并试图摆脱许多 gcc 警告。这些警告的很大一部分是关于有符号/无符号比较的,并且与size_t 的使用有关。该库适用于 64 位 Linux 系统。

程序员使用 -1 作为类似于std::string::npos 的特殊值。 库中有很多地方的代码是这样的:

class AnnotationBase
{
    public:
        size_t m_offset = -1;
        size_t m_length = -1;

}

...

AnnotationBase foo(const std::string& text, const AnnotationBase& annot)
{
    AnnotationBase newAnnot;

    // do some job with annotations and text
    ...

    if(newAnnot.m_offset == -1)
    {
        // do some other job
        ...
    }

    return newAnnot;
}

问题在于 gcc 在if(newAnnot.m_offset == -1) 行上由于有符号/无符号比较而生成的警告:

"warning: comparison between signed and unsigned integer expressions [-Wsign-compare]"

在没有警告的情况下将 C++ 中的 size_t 变量与最大值 (-1) 进行比较的正确方法是什么?由于这个表达式的复杂性和长度,像if(newAnnot.m_offset == std::numeric_limits<size_t>::max()) 这样的操作非常不方便。

使用 C 风格定义值 SIZE_MAX 是一种好方法,还是更好地创建自己的常量,如 namesapce libling { const NONE = std::numeric_limits<size_t>::max(); }(创建新常量会导致在不同的库和命名空间中出现许多类似的常量,如 libling::NONE、@ 987654331@, liblongnamesapcename::NOTHING)?

【问题讨论】:

  • 我当然会使用命名常量,例如if (newAnnot.m_offset == NoneOffset) ... ,然后可以声明为const size_t NoneOffset = -1;,这应该可以解决问题。使用您对NONE 的定义也可以。

标签: c++ comparison warnings unsigned-integer size-t


【解决方案1】:

你可以做std::string 所做的事情并定义一个static const size_t AnnotationBase::npos = -1。然后在比较中使用它作为惯例。我不会认为每个库一个常量是个问题,但如果你想避免这种情况,你可以直接使用std::string::npos(虽然这会使代码更加僵化)。

【讨论】:

    【解决方案2】:

    或者你可以使用this single header库来写

    if(sweet::equal(newAnnot.m_offset, -1))
    

    正如所指出的,这总是错误的,因为 size_t 不能存储 -1。但是比较不会产生任何警告,因为它可以正确和安全地处理不同的类型。此外,还有

    sweet::(less|lessEqual|notEqual|greater|greaterEqual)

    【讨论】:

      【解决方案3】:

      -1 的类型为 int。在比较之前,您需要通过static_cast 将其转换为std::size_tunsigned int

      【讨论】:

      • 是的。但是顺便比较 size_t 变量:if(newAnnot.m_offset == std::static_cast<size_t>(-1)) 也很不方便。
      • 我同意,但是从 -1 开始时你几乎没有选择。
      【解决方案4】:

      如果 -1 是合法值,则这些数据应该是 ssize_t。 将 -1 转换为 size_t 只是在欺骗编译器,并对 size_t 的其他正确值(尽管非常大)施加特殊含义。

      如果您坚持使用最高值来表示“无效”,请使用 SIZE_MAX 而不是 -1。

      【讨论】:

      • 嗯,这是一种处理问题的有趣方式,我认为在这种情况下它可能是一种选择。但是,据说 ssize_t 是一个扩展,它不包含在标准中,因此在其他情况下不可移植。
      • 顺便说一句,我认为带有-1 cast的作弊编译器肯定不好。关于特殊含义:std::string::npos 对 size_t 的最大值赋予特殊含义,所以看起来是合法的方式。
      • std::string::npos 只是一个静态 size_t 并分配了 -1。将 -1 分配/强制转换为 size_t 并没有什么“作弊”。
      • IMO 有很多方法可以欺骗编译器,它会构建可以工作的丑陋代码,一种方法是告诉编译器 size_t(或任何无符号原语)的值为 -1。请改用 SIZE_MAX。
      猜你喜欢
      • 1970-01-01
      • 2019-09-25
      • 1970-01-01
      • 1970-01-01
      • 2016-03-31
      • 2021-07-29
      • 2023-04-02
      • 2018-12-04
      • 2020-02-19
      相关资源
      最近更新 更多