【发布时间】:2017-10-21 02:18:40
【问题描述】:
对于常规 C 字符串,空字符 '\0' 表示数据结束。
std::string 怎么样,我可以有一个嵌入空字符的字符串吗?
【问题讨论】:
标签: c++ stdstring c-strings null-terminated
对于常规 C 字符串,空字符 '\0' 表示数据结束。
std::string 怎么样,我可以有一个嵌入空字符的字符串吗?
【问题讨论】:
标签: c++ stdstring c-strings null-terminated
是的,您可以在 std::string 中嵌入空值。
例子:
std::string s;
s.push_back('\0');
s.push_back('a');
assert(s.length() == 2);
注意:std::string 的c_str() 成员将始终将空字符附加到返回的字符缓冲区;但是,std::string 的 data() 成员可能会也可能不会将空字符附加到返回的字符缓冲区。
小心操作符+=
要注意的一件事是不要在 RHS 上使用 operator+= 和 char*。它只会累加到空字符。
例如:
std::string s = "hello";
s += "\0world";
assert(s.length() == 5);
正确方法:
std::string s = "hello";
s += std::string("\0world", 6);
assert(s.length() == 11);
存储二进制数据更常见于使用 std::vector
通常使用std::vector 来存储任意二进制数据更为常见。
std::vector<char> buf;
buf.resize(1024);
char *p = &buf.front();
这可能更常见,因为 std::string 的 data() 和 c_str() 成员返回 const 指针,因此内存不可修改。使用 &buf.front() 你可以直接修改缓冲区的内容。
【讨论】:
&s.front() 也是可修改的,并保证指向一个连续的缓冲区。虽然在 C++03 中没有这样的保证,但没有任何已知的 C++ 实现在实践中不适用(这也是它如此迅速地添加到 C++0x 的部分原因)。
.c_str() 和 .data 是同义词。特别是,这意味着.data 返回的字符串必须附加一个空终止符。
s.append("\0world", 6); 优于 s += std::string("\0world", 6);
是的。 std::string 只是一个有好处的vector<char>。
但是,请小心不要将这种野兽传递给调用.c_str() 并在 0 处停止的东西。
【讨论】:
你可以,但你为什么要这样做?在 std::string 中嵌入 NUL 只是自找麻烦,因为传递 std::string 的函数很可能会使用它的 c_str() 成员,并且大多数人会假设第一个 NUL 表示字符串的结尾。因此,这不是一个好主意。另请注意,在 UTF-8 中,只有 '\0' 会导致 0,因此即使出于 i18n 目的,也没有理由嵌入 NUL。
【讨论】:
std::string 的全部功能,因为您可能将c_str() 的结果传递给C 字符串函数而不传递长度”,真的吗?好吧,如果你从不这样做,你会没事的......
是的,这是有效的。
字符串中间可以有一个空字符。
但是,如果您使用中间有一个空字符的 std::string 和一个 c 字符串 在未定义的行为小镇中发挥作用 - 没有人愿意在那里!!!:
int n = strlen( strWithNullInMiddle.c_str() ); // Boom!!!
【讨论】:
strlen 将只返回第一个 null 之前的字符数。这可能是意料之外的行为,但并非未定义。