如何使用嵌入的null构造一个std :: string?

Bil*_*ill 82 c++ null stdstring

如果我想构造一个std :: string,其行如下:

std::string my_string("a\0b");
Run Code Online (Sandbox Code Playgroud)

我希望在结果字符串中有三个字符(a,null,b),我只得到一个.什么是正确的语法?

Mar*_*ork 123

从C++开始14

我们已经能够创建文字 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";
}
Run Code Online (Sandbox Code Playgroud)

在C++之前14

问题是std::string构造函数const char*假设输入是C字符串.C字符串被\0终止,因此解析在到达\0字符时停止.

为了弥补这一点,您需要使用从char数组(而不是C-String)构建字符串的构造函数.这需要两个参数 - 指向数组的指针和一个长度:

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.
Run Code Online (Sandbox Code Playgroud)

注意:C++ std::string \0封端的(如在其他职位的建议).但是,您可以使用该方法提取指向包含C-String的内部缓冲区的指针c_str().

另请参阅Doug T关于使用a 的回答vector<char>.

另请参阅RiaD以获取C++ 14解决方案.

  • @mna:它们在存储方面是空终止的,但不是因为它们是空终止的_具有有意义的null termination_(即使用字符串长度定义语义),这是该术语的通常含义. (14认同)
  • 更新:从c ++ 11开始,字符串以空值终止.话虽如此,Loki的帖子仍然有效. (6认同)

Dou*_* T. 22

如果您正在使用c风格的字符串(字符数组)进行操作,请考虑使用

std::vector<char>
Run Code Online (Sandbox Code Playgroud)

您可以更自由地像处理数组一样对待它,就像对待c字符串一样.您可以使用copy()复制到字符串中:

std::vector<char> vec(100)
strncpy(&vec[0], "blah blah blah", 100);
std::string vecAsStr( vec.begin(), vec.end());
Run Code Online (Sandbox Code Playgroud)

你可以在许多相同的地方使用它,你可以使用c字符串

printf("%s" &vec[0])
vec[10] = '\0';
vec[11] = 'b';
Run Code Online (Sandbox Code Playgroud)

然而,自然地,您遇到与c弦相同的问题.您可能会忘记空终端或写入已分配的空间.


17 *_* 26 13

我不知道你为什么要做这样的事情,但试试这个:

std::string my_string("a\0b", 3);
Run Code Online (Sandbox Code Playgroud)

  • 因为人们有时必须处理二进制数据? (29认同)
  • 如果你将二进制数据存储为字符串,那么@Constantin就会出错.这就是为什么发明了`vector <unsigned char>`或`unsigned char*`. (3认同)
  • @DuckMaestro不,那不是真的.UTF-8字符串中的`\ 0`字节只能是NUL.多字节编码字符永远不会包含`\ 0` - 也不包含任何其他ASCII字符. (3认同)
  • 我在尝试了解有关字符串安全性的更多信息时碰到了这一点。我想测试我的代码,以确保即使在从文件/网络读取期望为文本数据的同时读取空字符时,该代码仍能正常工作。我用`std :: string`表示该数据应被视为纯文本,但是我正在做一些散列工作,并且我想确保所涉及的所有空字符仍然有效。这似乎是对带有嵌入的空字符的字符串文字的有效使用。 (2认同)

小智 12

用户定义的文字为C++添加了哪些新功能?提出一个优雅的答案:定义

std::string operator "" _s(const char* str, size_t n) 
{ 
    return std::string(str, n); 
}
Run Code Online (Sandbox Code Playgroud)

然后你可以这样创建你的字符串:

std::string my_string("a\0b"_s);
Run Code Online (Sandbox Code Playgroud)

甚至是这样的:

auto my_string = "a\0b"_s;
Run Code Online (Sandbox Code Playgroud)

有一种"旧式"方式:

#define S(s) s, sizeof s - 1 // trailing NUL does not belong to the string
Run Code Online (Sandbox Code Playgroud)

然后你可以定义

std::string my_string(S("a\0b"));
Run Code Online (Sandbox Code Playgroud)


And*_*ein 8

以下将有效......

std::string s;
s.push_back('a');
s.push_back('\0');
s.push_back('b');
Run Code Online (Sandbox Code Playgroud)


Ria*_*iaD 6

在 C++14 中,您现在可以使用文字

using namespace std::literals::string_literals;
std::string s = "a\0b"s;
std::cout << s.size(); // 3
Run Code Online (Sandbox Code Playgroud)


Dav*_*one 5

你必须要小心这一点.如果用任何数字字符替换'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";
Run Code Online (Sandbox Code Playgroud)

以下是此程序为我输出的内容:

Entering loop.
Entering loop.

vector::_M_emplace_ba
QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ
Run Code Online (Sandbox Code Playgroud)

这是我的第一次打印声明两次,几个非打印字符,接着是换行符,然后是内部存储器中的内容,我刚刚覆盖(然后打印,显示它已被覆盖).最糟糕的是,即使用彻底和冗长的gcc警告编译它也没有给出任何错误的迹象,并且通过valgrind运行程序并没有抱怨任何不正确的内存访问模式.换句话说,现代工具完全无法检测到它.

你可以用更简单的方法解决同样的问题std::string("0", 100);,但上面的例子有点棘手,因此很难看出错误.

幸运的是,C++ 11使用初始化列表语法为我们提供了一个很好的解决方案.这使您无需指定字符数(如上所示,您可以正确执行),并避免组合转义的数字.std::string str({'a', '\0', 'b'})对于任何字符串内容都是安全的,与采用数组char和大小的版本不同.

  • 作为我为这篇文章做准备的一部分,我向gcc提交了一份错误报告,希望他们会添加一个警告,使其更加安全:http://gcc.gnu.org/bugzilla/show_bug.cgi?id = 54924 (2认同)