【问题标题】:Why does std::string("\x00") report length of 0?为什么 std::string("\x00") 报告长度为 0?
【发布时间】:2018-06-23 15:05:15
【问题描述】:

我有一个函数需要对字符串进行编码,它需要能够接受 0x00 作为有效的“字节”。我的程序需要检查字符串的长度,但是如果我将"\x00" 传递给std::stringlength() 方法会返回 0。

即使字符串是单个空字符,我如何才能获得实际长度?

【问题讨论】:

  • 查看available constructors 并在您的情况下使用。
  • 您也可以尝试strlen("\x00"); 以获得相同的结果。
  • @JackAidley 数据以字符串形式传入,一旦处理,它就会存储为字节向量。
  • @BoPersson, strlen(3) 不是 C++ 函数。这是一个 C 遗留函数,不知道 c++ string 类型。您不能将它与strings 一起使用,而是将string 转换为旧版C char * 字符串。这样,strlen(3) 不知道数组大小,它只搜索 \0 字符并返回传递给它的指针与找到空字符的位置之间的差异。

标签: c++ c++11 stdstring string-length


【解决方案1】:

std::string 完全能够存储空值。但是,您必须小心,因为const char* 不是,并且您非常简单地构造了一个const char*,并从中创建了std::string

std::string a("\x00");

这将创建一个仅包含空字符的常量 C 字符串,后跟空终止符。但是 C 字符串不知道它们有多长;所以字符串认为它一直运行到第一个空终止符,这是第一个字符。因此,创建了一个长度为零的字符串。

std::string b("");
b.push_back('\0');

std::string 是 null-clean。字符 (\0) 也可以是零字节。所以,在这里,没有什么能阻止我们正确读取数据结构。 b 的长度为1

通常,您需要避免构造包含空字符的 C 字符串。如果您将文件中的输入直接读入std::string 或确保一次推送一个字符,您可以获得您想要的结果。如果您确实需要一个带有空字符的常量字符串,请考虑使用其他标记字符而不是 \0,然后(如果您真的需要它)在加载到 @987654334 后将这些字符替换为 '\0' @。

【讨论】:

  • "但是 C 字符串不知道它们有多长" -- 更准确地说,std::string("\x00") 首先创建了一个字符串字面量 const char[2] 类型的,所以此时大小仍然是众所周知的。虽然这个数组衰减为const char*,它被传递给std::string构造函数。此时数组大小“丢失”,因为构造函数只能扫描第一个\0 以确定大小。理论上std::string c'tor 可能对数组有重载,这将允许在字符串文字中嵌入\0
  • @zett42 这样的重载必须模板化,并为数组的每个新长度进行实例化——在 C++ 中没有其他本地方法可以传递大小数组。
  • @Ruslan 所以?那将是完全可以接受的。当然,这也很愚蠢,因为它会破坏 C 字符串文字约定,因此在大多数情况下违反了用户的期望(在将其初始化为 std::string("hi") 时,没有人希望在其字符串中找到空字符)。跨度>
  • @KonradRudolph 因此,这将为传递给std::string::string 的每个字符串文字大小生成一个新函数。从代码大小的角度来看并不完美;你只需要希望链接器会忽略这些函数,编译器会将它们的代码内联到调用者中。
  • @Ruslan 代码内联不会减少代码大小。相反,为了帮助生成代码大小,构造函数模板可以分派给未内联的大小擦除非泛型函数。但是对于这个特定的构造函数,内联可能工作得很好,并且无论你有一个构造函数模板还是非模板构造函数(因为它是内联的),都会产生相同的代码大小。
【解决方案2】:

你传入一个空字符串。请改用std::string(1, '\0')

或者std::string{ '\0' }(谢谢@zett42)

【讨论】:

  • 短:std::string{ '\0' }
  • 可能巧合的是this question刚刚弹出。
  • @zett42:因为何时存在 std::string 的构造函数,只有一个 char 参数?
  • @CAF 从 C++11 开始。它是constructor that takes an initializer list (9)。
  • std::string("\0", 1),或std::string{ '\0' }
【解决方案3】:

使用 C++14,您可以使用 string literal operator 来存储具有空字节的字符串:

using namespace std::string_literals;

std::string a = "\0"s;
std::string aa = "\0\0"s; // two null bytes are supported too

【讨论】:

  • @sp2danny ...但也可能引入其他不需要的文字运算符(例如来自std::literals::chrono_literals)。
猜你喜欢
  • 2019-03-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-30
  • 2015-06-30
  • 2016-04-27
相关资源
最近更新 更多