C++ 你如何构造一个带有嵌入空值的 std::string ?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/164168/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do you construct a std::string with an embedded null?
提问by Bill
If I want to construct a std::string with a line like:
如果我想用如下一行构造一个 std::string:
std::string my_string("a#include <iostream>
#include <string>
int main()
{
using namespace std::string_literals;
std::string s = "pl-std::string x("pqstd::vector<char>
rs"); // Two characters because input assumed to be C-String
std::string x("pqstd::vector<char> vec(100)
strncpy(&vec[0], "blah blah blah", 100);
std::string vecAsStr( vec.begin(), vec.end());
rs",5); // 5 Characters as the input is now a char array with 5 characters.
-op"s; // <- Notice the "s" at the end
// This is a std::string literal not
// a C-String literal.
std::cout << s << "\n";
}
b");
Where i want to have three characters in the resulting string (a, null, b), I only get one. What is the proper syntax?
我想在结果字符串中包含三个字符(a、null、b),我只得到一个。什么是正确的语法?
回答by Martin York
Since C++14
从 C++14 开始
we have been able to create literal std::string
我们已经能够创造文字 std::string
printf("%s" &vec[0])
vec[10] = 'std::string my_string("astd::string operator "" _s(const char* str, size_t n)
{
return std::string(str, n);
}
b", 3);
';
vec[11] = 'b';
Before C++14
在 C++14 之前
The problem is the std::string
constructor that takes a const char*
assumes the input is a C-string. C-strings are \0
terminated and thus parsing stops when it reaches the \0
character.
问题在于假设输入是 C 字符串的std::string
构造函数const char*
。C 字符串被\0
终止,因此当它到达\0
字符时解析停止。
To compensate for this, you need to use the constructor that builds the string from a char array (not a C-String). This takes two parameters - a pointer to the array and a length:
为了弥补这一点,您需要使用从 char 数组(不是 C 字符串)构建字符串的构造函数。这需要两个参数 - 一个指向数组的指针和一个长度:
std::string my_string("aauto my_string = "a#define S(s) s, sizeof s - 1 // trailing NUL does not belong to the string
b"_s;
b"_s);
Note: C++ std::string
is NOT\0
-terminated (as suggested in other posts). However, you can extract a pointer to an internal buffer that contains a C-String with the method c_str()
.
注:C ++std::string
是不\0
封端的(如在其他职位的建议)。但是,您可以使用方法提取指向包含 C-String 的内部缓冲区的指针c_str()
。
Also check out Doug T's answerbelow about using a vector<char>
.
还检查了道格T的回答以下关于使用vector<char>
。
Also check out RiaDfor a C++14 solution.
另请查看RiaD以获取 C++14 解决方案。
回答by Doug T.
If you are doing manipulation like you would with a c-style string (array of chars) consider using
如果您像使用 c 样式字符串(字符数组)那样进行操作,请考虑使用
std::string my_string(S("astd::string s;
s.push_back('a');
s.push_back('// Create 'Entering loop.
Entering loop.
vector::_M_emplace_ba
QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ
' followed by '0' 40 times ;)
std::string str("using namespace std::literals::string_literals;
std::string s = "atemplate <size_t N>
std::string RawString(const char (&ch)[N])
{
return std::string(ch, N-1); // Again, exclude trailing `null`
}
b"s;
std::cout << s.size(); // 3
std::string my_string_t(RawString("astd::string s = S("a#define std::string(s, sizeof s - 1)
b"); // ERROR!
b"));
std::string my_string_m(S("aCComBSTR(20,"mystring1##代码##mystring2##代码##")
b"));
std::cout << "Using template: " << my_string_t << std::endl;
std::cout << "Using macro: " << my_string_m << std::endl;
##代码####代码####代码####代码####代码####代码####代码####代码####代码####代码####代码####代码####代码####代码####代码####代码####代码####代码####代码####代码####代码####代码####代码####代码####代码####代码####代码####代码####代码####代码####代码####代码####代码####代码####代码####代码####代码####代码##", 80);
std::cerr << "Entering loop.\n";
for (char & c : str) {
std::cerr << c;
// 'Q' is way cooler than '##代码##' or '0'
c = 'Q';
}
std::cerr << "\n";
for (char & c : str) {
std::cerr << c;
}
std::cerr << "\n";
');
s.push_back('b');
b"));
You have more freedom to treat it like an array in the same manner you would treat a c-string. You can use copy() to copy into a string:
您可以更自由地以与处理 c 字符串相同的方式将其视为数组。您可以使用 copy() 复制到字符串中:
##代码##and you can use it in many of the same places you can use c-strings
并且您可以在许多可以使用 c-strings 的相同地方使用它
##代码##Naturally, however, you suffer from the same problems as c-strings. You may forget your null terminal or write past the allocated space.
然而,自然地,您会遇到与 c-string 相同的问题。您可能会忘记您的空终端或写过分配的空间。
回答by 17 of 26
I have no idea whyyou'd want to do such a thing, but try this:
我不知道你为什么想做这样的事情,但试试这个:
##代码##回答by anonym
What new capabilities do user-defined literals add to C++?presents an elegant answer: Define
用户定义的文字为 C++ 添加了哪些新功能?给出了一个优雅的答案:定义
##代码##then you can create your string this way:
那么你可以这样创建你的字符串:
##代码##or even so:
甚至是这样:
##代码##There's an "old style" way:
有一种“老式”方式:
##代码##then you can define
然后你可以定义
##代码##回答by Andrew Stein
The following will work...
以下将工作...
##代码##回答by David Stone
You'll have to be careful with this. If you replace 'b' with any numeric character, you will silently create the wrong string using most methods. See: Rules for C++ string literals escape character.
你必须小心这一点。如果您将 'b' 替换为任何数字字符,您将使用大多数方法默默地创建错误的字符串。请参阅:C++ 字符串文字转义字符规则。
For example, I dropped this innocent looking snippet in the middle of a program
例如,我在程序中间丢弃了这个看起来很无辜的片段
##代码##Here is what this program output for me:
这是这个程序对我的输出:
##代码##That was my first print statement twice, several non-printing characters, followed by a newline, followed by something in internal memory, which I just overwrote (and then printed, showing that it has been overwritten). Worst of all, even compiling this with thorough and verbose gcc warningsgave me no indication of something being wrong, and running the program through valgrind didn't complain about any improper memory access patterns. In other words, it's completely undetectable by modern tools.
那是我的第一个打印语句两次,几个非打印字符,然后是一个换行符,然后是内部存储器中的某些内容,我刚刚将其覆盖(然后打印,表明它已被覆盖)。最糟糕的是,即使用彻底和详细的 gcc 警告编译它也没有给我任何错误的迹象,并且通过 valgrind 运行程序也没有抱怨任何不正确的内存访问模式。换句话说,现代工具完全无法检测到它。
You can get this same problem with the much simpler std::string("0", 100);
, but the example above is a little trickier, and thus harder to see what's wrong.
你可以用更简单的 来解决同样的问题std::string("0", 100);
,但上面的例子有点棘手,因此更难看出哪里出了问题。
Fortunately, C++11 gives us a good solution to the problem using initializer list syntax. This saves you from having to specify the number of characters (which, as I showed above, you can do incorrectly), and avoids combining escaped numbers. std::string str({'a', '\0', 'b'})
is safe for any string content, unlike versions that take an array of char
and a size.
幸运的是,C++11 使用初始化列表语法为我们提供了一个很好的解决方案。这使您不必指定字符数(正如我上面所展示的,您可能会做错),并避免组合转义数字。std::string str({'a', '\0', 'b'})
对任何字符串内容都是安全的,这与采用char
和大小的数组的版本不同。
回答by RiaD
In C++14 you now may use literals
在 C++14 中,您现在可以使用文字
##代码##回答by Kyle Strand
anonym's answer is excellent, but there's a non-macro solution in C++98 as well:
anonym 的回答很好,但在 C++98 中也有一个非宏解决方案:
##代码##With this function, RawString(/* literal */)
will produce the same string as S(/* literal */)
:
使用此函数,RawString(/* literal */)
将产生与以下相同的字符串S(/* literal */)
:
Additionally, there's an issue with the macro: the expression is not actually a std::string
as written, and therefore can't be used e.g. for simple assignment-initialization:
此外,宏还有一个问题:表达式实际上不是std::string
所写的 a,因此不能用于例如简单的赋值初始化:
...so it might be preferable to use:
...所以最好使用:
##代码##Obviously you should only use one or the other solution in your project and call it whatever you think is appropriate.
显然,您应该在您的项目中只使用一种或另一种解决方案,并以您认为合适的任何名称命名。
回答by Harold Ekstrom
Better to use std::vector<char> if this question isn't just for educational purposes.
如果这个问题不仅仅是出于教育目的,最好使用 std::vector<char> 。
回答by Dil09
I know it is a long time this question has been asked. But for anyone who is having a similar problem might be interested in the following code.
我知道这个问题已经问了很长时间了。但是对于遇到类似问题的任何人,可能会对以下代码感兴趣。
##代码##