【问题标题】:Unexpected strlen result for a string literal字符串文字的意外 strlen 结果
【发布时间】:2020-10-28 15:50:02
【问题描述】:
#include <iostream>
#include <cstring>

int main()
{   
    auto l = std::strlen("123\0456\0");
    std::cout << l << std::endl;
}

为什么这段代码的输出是 5?

我预计是 3 个。

这是一个在线版本进行测试: https://ideone.com/UQRKlV

【问题讨论】:

  • 存在需要谨慎处理的现有代码,但是如果您尝试编译此代码,不会有任何问题。为什么你不能自己回答这个问题?
  • 这里是现场版:https://ideone.com/UQRKlV
  • What will be the output of that code 你编译并检查输出是什么? also please explain why?您是否尝试过找出可能导致未显示所有内容的原因?
  • 为什么输出 5?当我将鼠标悬停在 VS 2019 中的字符串文字上时,它告诉我这是一个 const char[7] "123%6\000"。为什么\045 被视为%,为什么它将字符\045 组合在一起(而不是\0\04 或其他一些分块),以及为什么它以\000 终止\0?
  • 到目前为止没有一个答案提到这一点,但是您可以使用 auto l = std::strlen("123\0" "456\0"); 构建您期望的字符串文字。

标签: c++ string strlen


【解决方案1】:

"123\0456\0"const char[7] 类型的文字

\045 是单个字符,以八进制指定。在 ASCII 中,它是 '%'。这里\0表示NUL,因为最大咀嚼解析规则将\045提取为八进制转义序列:注意0 、4 和 5 是有效的八进制数字,并且八进制转义序列不能超过 3 位。

第二个\0 是一个显式的NUL,在文字的末尾还有一个隐含的额外NUL

strlen 将返回 5,因为在第一个 NUL 之前有很多字符。

【讨论】:

  • 为了明确起见,第一个 \0 不是空字符,因为它后面还有两个八进制有效数字。所以这些数字是转义序列的一部分。
  • @FredLarson:没错!值得添加。
  • 那么\0456 不是一个有效的转义序列吗?如果我只写char c = 0456; std::cout &lt;&lt; c;,它会在终端上打印.。调用 UB 是因为 302 不是有效的 ASCII 值吗?
  • @NathanPierson:八进制转义序列最多为三位数。
  • @NathanPierson 0456 没有以任何方式转义(没有前导\),它只是一个普通的八进制形式的integer literal。编译器会将int 值(八进制456,十进制302)按原样隐式转换为char,但char 可以容纳的最大值是十进制127(八进制177),因此char 将溢出,在您的情况下发生会产生一个十进制 46(八进制 56)的 char 值,这是 ASCII 字符 .
【解决方案2】:

文字中的字符可以是 escaped,使用十六进制 (\xNN)、八进制 (\0NN) 或 Unicode (\uNNNN\UNNNNNNNN) 表示法。

在您的字符串文字中,"123\0456\0"\045\0 是八进制转义序列。

您期望编译器将第一个 \0 解析为 NUL 终止符的 1 位八进制序列,但实际上它被解析为 3 位八进制序列,因为八进制最多使用 3 位, 0、4 和 5 是有效的八进制数字。因此编译器会将 3 位 \045 序列解析为单个 char,其数值为八进制 45(十进制 37,十六进制 0x25),在 大多数(不是全部)字符集中是ASCII % 字符,它会将第二个 1 位 \0 序列解析为单个 char,其数值为八进制 0(十进制 0,十六进制 0x00),在所有字符集中都是 NUL字符。

所以,"123\0456\0" 总共有 7 个chars(包括末尾的隐式空终止符):

1 2 3 % 6 NUL NUL

strlen() 将计数chars,直到遇到NUL 字符。这就是为什么输出是 5,而不是 3。

【讨论】:

    【解决方案3】:

    首先阅读string literals in C++。寻找escape sequences的特殊含义。

    然后阅读 strlen 所做的事情并结合这些知识来解释结果。

    【讨论】:

    • 相关引用重新。转义序列:“八进制转义序列的限制为三个八进制数字,但如果更早遇到,则在第一个不是有效八进制数字的字符处终止。”
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-18
    • 2023-01-27
    • 1970-01-01
    • 1970-01-01
    • 2013-10-14
    • 2018-04-29
    相关资源
    最近更新 更多