在C ++中,您可以从std::string
和char *
初始化const char *
对象,这隐含地假设字符串将在指针后找到的第一个NUL
字符处结束
在C ++中,字符串文字是数组,即使字符串文字包含嵌入的NUL
,也可以使用模板构造函数来获取正确的大小。例如,参见以下玩具实现:
#include <stdio.h>
#include <string.h>
#include <vector>
#include <string>
struct String {
std::vector<char> data;
int size() const { return data.size(); }
template<typename T> String(const T s);
// Hack: the array will also possibly contain an ending NUL
// we don't want...
template<int N> String(const char (&s)[N])
: data(s, s+N-(N>0 && s[N-1]=='\0')) {}
// The non-const array removed as probably a lot of code
// builds strings into char arrays and the convert them
// implicitly to string objects.
//template<int N> String(char (&s)[N]) : data(s, s+N) {}
};
// (one tricky part is that you cannot just declare a constructor
// accepting a `const char *` because that would win over the template
// constructor... here I made that constructor a template too but I'm
// no template programming guru and may be there are better ways).
template<> String::String(const char *s) : data(s, s+strlen(s)) {}
int main(int argc, const char *argv[]) {
String s1 = "Hello\0world\n";
printf("Length s1 -> %i\n", s1.size());
const char *s2 = "Hello\0world\n";
printf("Length s2 -> %i\n", String(s2).size());
std::string s3 = "Hello\0world\n";
printf("std::string size = %i\n", int(s3.size()));
return 0;
}
是否有任何特定的技术原因,对于标准没有考虑这种方法,而是在用于初始化NUL
对象时,嵌入std::string
的字符串文字会被截断?< / p>
答案 0 :(得分:4)
C ++ 14为字符串文字引入了一个后缀,使它们成为std::string
个对象,因此主要用例不再相关。
#include <iostream>
#include <string>
using namespace std;
using namespace std::literals;
int main() {
string foo = "Hello\0world\n";
string bar = "Hello\0world\n"s;
cout << foo.size() << " " << bar.size() << endl; // 5 12
cout << foo << endl; // Hello
cout << bar << endl; // Helloworld
return 0;
}
答案 1 :(得分:2)
使用包含嵌入式nullbytes的文字初始化std::string
需要将起始指针和长度都传递给构造函数。
如果有专门的take-array-reference构造函数模板,这是最简单的,但正如你所注意的那样
这样的模板,只有 数组参数,被认为是比构造函数更简单的匹配char const*
和
目前尚不清楚是否应包括最终的终止零值。
第一点意味着物理代码接口将是一个模板化构造函数,其中只有文档(而不是编辑器的工具提示)才会告诉完整的故事它是什么意思。一个解决方法是引入一个额外的虚拟解析器参数。这降低了便利性。
第二点是引入错误的机会。毫无疑问,构造函数最常见的用法是普通的字符串文字。然后,它会偶尔用于带有嵌入式nullbytes的文字和/或数组,但奇怪的是最后一个字符被砍掉。
相反,人们可以简单地命名该值,
char const data[] = "*.com\0*.exe\0*.bat\0*.cmd\0";
string s( data, data + sizeof( data ) ); // Including 2 nulls at end.
所有这一切,当我已经定义了我自己的字符串类时,我已经包含了take-array-argument构造函数,但原因与方便不同。即,在文字的情况下,字符串对象可以简单地保持该指针而不进行复制,这不仅提供了效率,而且提供了例如安全性(正确性)。例外。一个const char
数组是我们在C ++ 11及更高版本中最清晰的文字表示。
但是,std::string
无法做到这一点:它不是为它设计的。
如果经常这样做,那么可以定义这样的函数:
using Size = ptrdiff_t;
template< Size n >
auto string_from_data( char const (&data)[n] )
-> std::string
{ return std::string( data, data + n ); }
然后就可以写
了string const s = string_from_data( "*.com\0*.exe\0*.bat\0*.cmd\0" );
免责声明:编译器未触及或看到任何代码。
[我在第一次写作时错过了这个,但Hurkyl's answer提醒我。现在去喝咖啡了!]
C ++ 14字符串类型文字会从最终的\0
中删除,所以对于这样的文字,上面必须包括明确终止nullvalue:
string const s = "*.com\0*.exe\0*.bat\0*.cmd\0\0"s;
除此之外,C ++ 14字符串类型文字似乎提供了方便的搜索。