【问题标题】:Why "if (unsigned int == string::npos )" CAN be true?为什么“if (unsigned int == string::npos)”可以是真的?
【发布时间】:2021-01-21 12:38:16
【问题描述】:

首先让我说:很抱歉,如果这被解释了,我尝试阅读它并寻找答案,但我没有找到回答这个特定问题的答案。

所以我正在用 C++ 编写初学者级别的代码,并且我编写了一个非常简单的函数,它返回下一个找到的非空格字符的索引。它的灵感来自方法 string.find()。 如果该函数没有找到任何内容,则返回 string::npos。

int findChar (const string &line, const int startPos){
    for (unsigned int i= startPos; i < line.length(); i++){
        if ( line[i] != ' ') return i;
    }
    return string::npos;
}

现在,因为我正在处理字符串和索引,所以我想到了使用无符号整数。

unsigned int where;
where = findChar(line, 0);

因为“where”是一个无符号整数,我认为比较“where == string::npos”是个坏主意,因为 string::npos 是用 -1 初始化的,而 unsigned int 不能等于 - 1.但是如果函数没有找到任何东西并且它返回 string::npos 条件可以为真,程序会识别出“unsigned int where”是 string::npos,但是当我尝试打印“where”时,它会打印输出为 unsigned int 可以容纳的最大数字。

所以我的问题是,为什么或如何,程序可以识别 unsigned int 等于 string::npos,即使从技术上讲 string::npos 的值初始化为 -1。

我正在努力学习,所以如果你能指出一些可以回答这个问题的阅读材料,我将不胜感激。

【问题讨论】:

  • 打印std::string::npos,你会感到惊讶。请注意,您的代码仅在 32 位平台上“有效”,其中 std::size_t 的大小与 unsigned int 相同。
  • string::npos 被定义为static const size_t npos = -1;std::size_t is the unsigned integer type of the result of the sizeof operator 所以当-1 被分配给一个size_t 对象时,它被转换为一个与-1 具有相同位模式的无符号值。跨度>
  • 1., 2., 3. 请妥善保管。
  • 那个函数findChar 很奇怪。它返回int,而iunsigned intstd::string::npossize_t
  • @JerryJeremiah 位模式可能不同(在 64 位系统或非 2 的补码系统上)。转换是根据模运算下的值定义的

标签: c++


【解决方案1】:

如果你读到the documentation

虽然定义使用-1,但size_type是无符号整数类型,npos的值是它可以容纳的最大正值,由于有符号到无符号的隐式转换。这是一种指定任何无符号类型的最大值的可移植方式。

注意:std::string::npos 的类型为 size_t。使用其他任何东西可能是未定义的行为,并且不建议

【讨论】:

  • 使用其他类型可能行不通,但我认为它本身不是UB。
  • @HolyBlackCat 这不正是“可能行不通”在实践中的意思吗?
  • @tadman UB 具有明确定义的含义(也许具有讽刺意味),可能存在未按预期运行但不是未定义行为的代码。
  • @M.M 除非你能找到将npos 存储在其预期类型之外的任何位置的位置是已定义,那么我建议它是未定义我>。我确信通过其他显式规则允许进行一些转换,但是没有多少东西能够毫无问题地代表size_t
  • @tadman 这不是未定义的行为,无论该问题的答案如何
【解决方案2】:

string::npos 是一个很大的正数。

为避免这些问题,您的函数的返回类型应与您返回的值的类型相匹配,例如:

  • 返回string::size_type 而不是int,或者:
  • 在第一个代码中返回一些其他故障标记,例如 -1

按照您现在的方式,当适合返回类型的“调整”值恰好与有效返回值相同时,总是会发生冲突。

虽然npos 可能在实现标头中使用-1 进行初始化,但这并不意味着它的值是-1。初始化器被转换为被初始化对象的类型,即string::size_type,保证为无符号类型。这种转换的结果是一个很大的正值。


注意。如果在长于 UINT_MAX 字符的字符串上调用您的代码,您的代码将会严重中断,因为 i 循环永远不会结束。 i 也应该是 string::size_type 而不是 int;类似的考虑也适用于startPos 参数。

【讨论】:

    猜你喜欢
    • 2016-02-26
    • 2011-07-03
    • 1970-01-01
    • 2018-09-09
    • 1970-01-01
    • 2016-05-28
    • 1970-01-01
    • 2019-02-08
    • 2021-08-07
    相关资源
    最近更新 更多