如果我想用这样的一行构造一个 std::string:
std::string my_string("a\0b");
我想在最终的字符串中包含三个字符(a,null,b),但我只得到了一个。正确的语法是什么?
我希望最终的字符串包含三个字符(a,null,b),但我只得到了一个。请问应该使用什么正确的语法?
我们可以创建literal std::string
。
#include <iostream>
#include <string>
int main()
{
using namespace std::string_literals;
std::string s = "pl-\0-op"s; // <- Notice the "s" at the end
// This is a std::string literal not
// a C-String literal.
std::cout << s << "\n";
}
问题出在std::string
构造函数中接受const char*
参数的假定输入是一个C字符串。C字符串以\0
结尾,因此当遇到\0
字符时解析停止。
为了弥补这个问题,你需要使用从char数组(而不是C字符串)构建字符串的构造函数。它需要两个参数 - 一个指向数组的指针和一个长度:
std::string x("pq\0rs"); // Two characters because input assumed to be C-String
std::string x("pq\0rs",5); // 5 Characters as the input is now a char array with 5 characters.
如果您正在执行与C风格字符串(字符数组)类似的操作,请考虑使用
std::vector<char>
您可以更像对待C字符串一样自由地将其视为数组。您可以使用copy()函数将其复制到一个字符串中:
std::vector<char> vec(100)
strncpy(&vec[0], "blah blah blah", 100);
std::string vecAsStr( vec.begin(), vec.end());
你可以在许多与c字符串相同的地方使用它
printf("%s" &vec[0])
vec[10] = '\0';
vec[11] = 'b';
然而,与 C 字符串一样,您自然也会遇到同样的问题。可能会忘记添加空终止符或超出分配的空间。
std::memcpy(bytes, image.data, dataSize * sizeof(byte));
std::string test(reinterpret_cast(bytes));
std::cout << "Encoded String length " << test.length() << std::endl;```
- Alex Punnen我不知道为什么你想做这样的事情,但可以尝试以下操作:
std::string my_string("a\0b", 3);
vector<unsigned char>
或unsigned char*
所发明的。 - Mahmoud Al-Qudsistd::string
来表示数据应被视为纯文本,但我正在进行一些哈希处理,并且我想确保所有内容都可以处理包含空字符的情况。这似乎是使用嵌入空字符的字符串字面量的有效用法。 - David Stone\0
字节只能是NUL。一个多字节编码的字符永远不会包含\0
——也不包含任何其他ASCII字符。 - John Kugelman什么新功能由C++的用户定义字面常量添加?展示了一个优雅的答案:定义
std::string operator "" _s(const char* str, size_t n)
{
return std::string(str, n);
}
那么,你可以用以下方式创建你的字符串:
std::string my_string("a\0b"_s);
或者甚至如此:
auto my_string = "a\0b"_s;
有一个“旧风格”的方法:
#define S(s) s, sizeof s - 1 // trailing NUL does not belong to the string
那么您可以定义
std::string my_string(S("a\0b"));
std::string s;
s.push_back('a');
s.push_back('\0');
s.push_back('b');
using namespace std::literals::string_literals;
std::string s = "a\0b"s;
std::cout << s.size(); // 3
auto s{"a\0b"s};
。 - underscore_d您需要小心处理这个问题。如果您将 'b' 替换为任何数字字符,则大多数方法会悄悄地创建错误的字符串。请参阅:C ++字符串文字转义字符规则。
例如,我将这个看似无害的片段放在程序的中间
// Create '\0' followed by '0' 40 times ;)
std::string str("\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00", 80);
std::cerr << "Entering loop.\n";
for (char & c : str) {
std::cerr << c;
// 'Q' is way cooler than '\0' or '0'
c = 'Q';
}
std::cerr << "\n";
for (char & c : str) {
std::cerr << c;
}
std::cerr << "\n";
Entering loop.
Entering loop.
vector::_M_emplace_ba
QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ
std::string("0", 100);
中遇到同样的问题,但上面的例子更加棘手,因此更难看出问题所在。char
数组和一个大小的版本不同,std::string str({'a', '\0', 'b'})
对于任何字符串内容都是安全的。anonym的回答很好,但在C++98中也有非宏解决方案:
template <size_t N>
std::string RawString(const char (&ch)[N])
{
return std::string(ch, N-1); // Again, exclude trailing `null`
}
RawString(/*文本*/)
将会产生与S(/*文本*/)
相同的字符串:std::string my_string_t(RawString("a\0b"));
std::string my_string_m(S("a\0b"));
std::cout << "Using template: " << my_string_t << std::endl;
std::cout << "Using macro: " << my_string_m << std::endl;
std::string
,因此不能用于简单的赋值初始化。std::string s = S("a\0b"); // ERROR!
#define std::string(s, sizeof s - 1)
我知道这个问题已经被问了很长时间。但是对于任何遇到类似问题的人,可能会对以下代码感兴趣。
CComBSTR(20,"mystring1\0mystring2\0")