-1

我有以下字符串:

index                                       0   1   2   3   4   5   6   7
std::string myString with the content of "\xff\xff\xff\x00\xff\x0d\x0a\xf5"

当我引用 myString[3] 时,我得到了预期的 '\x00' 值。

但是当我提到 myString[5] 时,我得到了两个值“\x0d\x0a”,而不仅仅是“\x0d”。

更有趣的是 myString[6] 值,即 '\xf5'。这次就像 \x0d 不存在并且引用了正确的位置。

我的问题是:std:string 对象中的 \x0d 字符有什么特别之处?索引时如何跳过它?就像这样计算:

index                     0   1   2   3   4   5   5   6
std::string myString = "\xff\xff\xff\x00\xff\x0d\x0a\xf5"

作为注释,'\x0d' 字符是第 13 个 ASCII 字符“回车”,而 '\x0a' 是换行符。

更新: std::string 是否将 "\x0d\x0a" 视为单个字符,因此仅在字符串中占据一个位置?这个 '\x0d' 是关于 std::string 的“神秘”字符吗?

附加信息:http ://en.wikipedia.org/wiki/Newline

4

5 回答 5

9

你确定这正在发生std::string吗?std::string::operator[]返回 a const char &,那么它如何返回两个字符('\x0d' '\x0a')?

也就是说,"\x0d\x0a"通常用于 Windows 下的行尾,而 only'\x0a'用于 Linux 下,因此在 Windows 下将前者转换为后者是相对常见的——例如,我正在考虑用 .fopen调用时的行为"wt"。我猜类似的事情正在发生在你身上。

编辑:根据您对原始问题的评论,我想我可以猜到发生了什么。

我相信您的字符串并不真正包含您认为它包含的内容。您被误导了,因为您用于将字符串输出到文件的机制(可能ofstream?)正在执行行尾翻译。这意味着 a '\n'(Unix end-of-line code) 正在被翻译成'\r\n'(Windows end-of-line code)。行尾翻译的目的是使代码在操作系统之间更具可移植性。您可以通过以二进制模式打开文件来禁止它;对于ofstream,这是通过ios_base::binary在打开文件时指定标志来完成的,但默认情况下不设置此标志。

(有关不同操作系统上的行尾标记的更多信息,请参阅此Wikipedia 文章。)

这就是我相信正在发生的事情。您的字符串实际上包含

index                 0   1   2   3   4   5   6
myString contents  "\xff\xff\xff\x00\xff\x0a\xf5"

您正在输出如下内容:

ofstream file("myfile.txt");
for(size_t i=0; i<myString.size(); i++)
    ofstream << myString[i];

由于上面解释的行尾翻译,'\x0a'inmyString[5]被输出为'\x0d\x0a',这就是让你感到困惑的地方。

于 2009-09-02T08:11:44.037 回答
9

这里出错的一件事是以下行没有达到您的预期:

std::string myString = "\xff\xff\xff\x00\xff\x0d\x0a\xf5";

这将调用std::string(const char *)构造函数,该构造函数旨在将 C 风格的以空字符结尾的字符串转换为 C++ std::string。这个构造函数从给定的指针开始读取字节并将它们复制到新的std::string,直到它到达一个空字节(\x00)。这与 C 函数的行为一致,例如strlen().

所以,当你myString被构造时,它由一个长度为 3 的字符串组成,字节为 \xff、\xff、\xff。访问大于 2 的索引是访问数组末尾的字节(这将产生最好的运行时错误,或者最坏的情况是未定义的行为)。

请注意,astd::string可以保存中间空字节,但您不能使用上述构造函数来初始化这样的字符串,因为空字节被解释为终止传递给构造函数的 C 样式字符串。

将 \x00 字节更改为其他内容,再次尝试您的代码是值得的,只是为了看看它与您已经描述的内容有何不同:

std::string myString = "\xff\xff\xff\x01\xff\x0d\x0a\xf5"

另外,检查myString.length()上面的构造函数,看看你得到了什么。

于 2009-09-02T09:02:32.313 回答
2

您使用以下构造函数创建字符串:string(char const *)

它接收 NUL 终止的 C 字符串。所以它根据第一个0字符找到它的长度。

您应该使用其他指定大小的构造函数:string(char const *,size_t n)通过调用:

std::string myString("\xff\xff\xff\x00\xff\x0d\x0a\xf5",8);

请参阅http://www.cplusplus.com/reference/string/string/string/进一步阅读

于 2009-09-02T09:07:47.810 回答
0

您可能误用了 [] 运算符。

[] 运算符返回一个 const 字符。但是,您可能将其用作指针并因此得到两个字符 - 我们需要查看您的实际代码来确认这一点。

0x00 是 c 字符串的空终止符,所以这可能就是为什么你只得到一个(正确的)字符的原因。

当你得到 [4] 时会发生什么?

于 2009-09-02T08:21:07.060 回答
0

在 Visual Studio 2008 中,\x00 被认为是字符串的结尾。所以 myString.lenght 返回 3。当您尝试访问 myString[5] 时,您会收到错误消息。

于 2009-09-02T08:42:31.493 回答