C++ 使用类似strndup的语义从char[]创建std::string

C++ 使用类似strndup的语义从char[]创建std::string,c++,constructor,stdstring,C++,Constructor,Stdstring,我有一个 char txt_msg[80]; 数组最多可包含80个字符,例如,不能保证存在终止null。但是,如果少于80个字符,则会出现终止null 现在,我使用它从以下内容中获取std::字符串: std::string(txt_msg, txt_msg + ::strnlen(txt_msg, sizeof(txt_msg))); 创建一个C++字符串,看起来有点冒犯。有没有比C++y更适合的方法 有没有比C++y更适合的方法 就std::string的构造而言,实际上并不是这样。不过

我有一个

char txt_msg[80];
数组最多可包含80个字符,例如,不能保证存在终止null。但是,如果少于80个字符,则会出现终止null

现在,我使用它从以下内容中获取std::字符串:

std::string(txt_msg, txt_msg + ::strnlen(txt_msg, sizeof(txt_msg)));

创建一个C++字符串,看起来有点冒犯。有没有比C++y更适合的方法

有没有比C++y更适合的方法

std::string
的构造而言,实际上并不是这样。不过,至少,由于您已经知道
char[]
的最大长度,您可以使用
std::string(const char*,size_type)
构造函数而不是
std::string(InputIt,InputIt)
构造函数,因此构造函数可以避免计算长度:

std::string(txt_-msg,::strnlen(txt_-msg,sizeof(txt_-msg));
由于
strnlen()
是一个非标准的POSIX扩展,因此编写手动实现并不困难,如果需要:

#包括
大小字符串(常量字符*s,大小字符串)
{
const char*s_end=s+maxlen;
const char*found=std::find(s,s_end,“\0”);
返回(已找到!=s_end)?大小(已找到-s):maxlen;
}

,对于你的问题,C++解决方案是在助手模板函数中封装<>代码STD::String 构造,如:

模板
std::字符串到_字符串(const char(&arr)[N])
{
返回std::string(arr,strnlen(arr,N));
}
然后,您可以在需要时执行此操作:

char txt_msg[80];
...
std::string s=to_string(txt_msg);
而不是这样做:

char txt_msg[80];
...
std::string s=std::string(txt_-msg,txt_-msg+strnlen(txt_-msg,sizeof(txt_-msg));
//或
std::string s=std::string(txt_msg,strnlen(txt_msg,sizeof(txt_msg));

我可能会这样做:

char txt_msg[80];

auto s = std::string(std::begin(txt_msg), std::find(std::begin(txt_msg), std::end(txt_msg), '\0'));

将返回第一个空终止符或数组末尾的位置。

也许你应该考虑使用一个非拥有字符串的引用类型,它可以主要用于<代码> STD::String < /C> >;在你的情况下,它将被你的消息数组支持:

auto sv = std::string_view{txt_msg, ::strnlen(txt_msg, std::extent_v<decltype(txt_msg)>};
有了这个,你可以写:

auto sv = constrain_by_nul(std::string_view{txt_msg, std::size(txt_msg)});
更好,但还不完全是这样:我们提到了两次
txt\u msg
。不幸的是,我们不能直接从容器(IIANM)构造字符串视图。那么可能是另一个实用函数

template<typename CharT, std::size_t N> 
std::basic_string_view<CharT>
inline make_string_view(CharT (&arr)[N]) { 
    return {arr, N};
};
这正是您首先想要做的。通过适当的编译器优化,它实际上可能编译成相同的东西。而且-没有复制和堆分配,因为它不是
std::string



阅读有关此SO问题中字符串视图的更多信息:

如果添加了空终止符,填充数组的函数是否会“返回”它填充的字符数?或者“返回”其他一些指示符?您可以使用
(char*,size)执行
std::string(txt_msg,::strnlen(txt_msg,sizeof txt_msg));
< /COD>构造函数而不是<代码>(开始,结束)< /C>构造函数。显然,代码< StnLLNE/CODE>不是C或C++标准(它是POSIX。1-2008),但写起来并不难。@Someprogrammerdude不,这是在一个由C库填充的结构中。我只得到填充的结构。
看起来有点冒犯性
我不觉得冒犯,看起来不错。@Remy我同意它并不比使用
strnlen
更有效……但从某种意义上说它“更好”t不依赖可用的非标准函数。这假设OP可以访问实际数组,并且它没有衰减到指针。@Someprogrammerdude如果这是真的,此代码甚至不会编译。@einpoklum
std::to_string()
只支持数字类型,不支持字符数组。并且没有
sizeof()
在我的“最后建议”中。你指的是什么干的违规行为?好吧,那么-我会犹豫是否有人给_string()写
该函数还有其他功能。可能函数的名称不同?@einpoklum可以随意命名。我更喜欢使用与standard@einpoklum请再仔细阅读我的答案。你指的是我说过不要使用的代码,这与OP的原始代码有关。哦,是的,对不起,我跳了一步行。另一点是,您强制
to_string()
的用户猜测字符串长度是否始终是数组大小,或者有时小于数组大小。这并不明显。而且名称的选择也不明显。最后,在
to_string()的实现中,您仍然使用仅限POSIX的函数
虽然您有足够好的标准库设施可以使用。
std::extent\u v
可以用
std::size(txt\u msg)
代替。
make\u string\u view()
可以原样使用
arr
代替
std::begin(arr)
N
而不是
std::end(arr)
返回std::string\u视图{arr,N};
我不知道
std::size()
,谢谢!关于string\u视图构造的观点很好。我已经进一步改进了它。。。
template<typename CharT, std::size_t N> 
std::basic_string_view<CharT>
inline make_string_view(CharT (&arr)[N]) { 
    return {arr, N};
};
auto sv = constrain_by_nul(make_string_view(txt_msg));