[英]Copy null terminated char array to std::string respecting buffer length
Maybe it's just the lack of coffee, but I'm trying to create a std::string
from a null-terminated char
array with a known maximum length and I don't know, how to do it. 也许只是缺少咖啡,但我正在尝试从已知最大长度的以null结尾的
char
数组创建一个std::string
,我不知道,怎么做。
auto s = std::string(buffer, sizeof(buffer));
.. was my favorite candidate but since C++ strings are not null-terminated this command will copy sizeof(buffer)
bytes regardless of any contained '\\0'. ..是我最喜欢的候选者,但由于C ++字符串不是以空值终止的,因此该命令将复制
sizeof(buffer)
字节,而不管是否包含'\\ 0'。
auto s = std::string(buffer);
.. copies from buffer
until \\0
is found. ..从
buffer
复制,直到找到\\0
。 This is almost what I want but I can't trust the receive buffer so I'd like to provide a maximum length. 这几乎是我想要的,但我不能相信接收缓冲区,所以我想提供一个最大长度。
Of course, I can now integrate strnlen()
like this: 当然,我现在可以像这样集成
strnlen()
:
auto s = std::string(buffer, strnlen(buffer, sizeof(buffer)));
But that seems dirty - it traverses the buffer twice and I have to deal with C-artifacts like string.h
and strnlen()
(and it's ugly). 但这看起来很脏 - 它遍历缓冲区两次,我必须处理像
string.h
和strnlen()
这样的C工件(而且它很难看)。
How would I do this in modern C++? 我如何在现代C ++中做到这一点?
const char* end = std::find(buffer, buffer + sizeof(buffer), '\0');
std::string s(buffer, end);
Something like this could work in a single pass.. 像这样的东西可以一次通过..
auto eos = false;
std::string s;
std::copy_if(buffer, buffer + sizeof(buffer), std::back_inserter(s),
[&eos](auto v) {
if (!eos) {
if (v) {
return true;
}
eos = true;
}
return false;
});
If you want a single-pass solution, start with this: 如果您需要单程解决方案,请从以下开始:
template<class CharT>
struct smart_c_string_iterator {
using self=smart_c_string_iterator;
std::size_t index = 0;
bool is_end = true;
CharT* ptr = nullptr;
smart_c_string_iterator(CharT* pin):is_end(!pin || !*pin), ptr(pin) {}
smart_c_string_iterator(std::size_t end):index(end) {}
};
now, gussy it up and make it a full on random-access iterator. 现在,谨慎起来,让它在随机访问迭代器上变得完整。 Most of the operations are really simple (
++
etc should advance both ptr
and index
), except ==
and !=
. 除了
==
和!=
之外 ,大多数操作都非常简单( ++
等应该推进ptr
和index
)。
friend bool operator==(self lhs, self rhs) {
if (lhs.is_end&&rhs.is_end) return true;
if (lhs.index==rhs.index) return true;
if (lhs.ptr==rhs.ptr) return true;
if (lhs.is_end && rhs.ptr && !*rhs.ptr) return true;
if (rhs.is_end && lhs.ptr && !*lhs.ptr) return true;
return false;
}
friend bool operator!=(self lhs, self rhs) {
return !(lhs==rhs);
}
we also need: 我们还需要:
template<class CharT>
std::pair<smart_c_string_iterator,smart_c_string_iterator>
smart_range( CharT* ptr, std::size_t max_length ) {
return {ptr, max_length};
}
now we do this: 现在我们这样做:
auto r = smart_range(buffer, sizeof(buffer));
auto s = std::string(r.first, r.second);
and at each step we check for both buffer length and null termination when doing the copy. 在执行复制时,我们在每一步检查缓冲区长度和空终止。
Now, Ranges v3 brings about the concept of a sentinal, which lets you do something like the above with reduced runtime cost. 现在,Ranges v3带来了一个sentinal的概念,它允许你做一些类似上面的事情,降低运行时成本。 Or you can hand-craft the equivalent solution.
或者你可以手工制作同等的解决方案。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.