【问题标题】:C++ getline() behaves strangely when reading stringstream containing \0 [duplicate]C ++ getline()在读取包含\ 0的字符串流时表现异常[重复]
【发布时间】:2014-11-28 03:17:48
【问题描述】:

我正在尝试从使用 \0 来分隔数据片段和 \n 来分隔行的套接字中读取一个大缓冲区。

我认为 getline() 是获取每一行的简单方法,但它的行为很奇怪。

我在 getline() 中使用 \n 作为分隔符。

string line;
string test1 = "aaa,123\nbbb\nccc,456\n";
stringstream ss1(test1);
while(std::getline(ss1, line, '\n')) {
    cout << line << endl;
    }
// outputs:
// aaa,123
// bbb
// ccc,456

string test2 = "aaa\0123\0\nbbb\0\nccc\0456\0\n";
stringstream ss2(test2);
while(std::getline(ss2, line, '\n')) {
    cout << line << endl;
    }
// outputs:
// aaa
// 3

为什么在 test2 中会发生这种情况? 3从哪里来?我必须删除 \0 才能完成这项工作吗?当我执行套接字 recv() 时,是否有更简单/更好的方法来标记缓冲区中的字符串?

【问题讨论】:

  • 为什么来自套接字的数据首先在行中有空值?如果它应该是文本,则不应嵌入空值。
  • 哦,我知道 3 是从哪里来的。第一个\0 不是空值,它是\012 的开头,它是一个回车符。然后是 3。
  • 是换行,不是回车。 CR 是\015。 LF 也是 C 换行符。

标签: c++ sockets getline stringstream


【解决方案1】:

\0 使用特殊符号。它显示字符串何时结束。

例如,如果您输入"a string",编译器会自动在末尾添加一个\0,表示字符串的结束。但是,在字符串中间有一个\0 是合法的,它只是意味着它后面的所有内容都被忽略了。

所以基本上,您对字符串执行的任何操作,而不仅仅是getline,都会将字符串视为"aaa",忽略找到的第一个\0 之后的所有内容。但是……

正如@Fred Larson 指出的那样

哦,我知道 3 是从哪里来的。第一个 \0 不是空值,它是 \012 的开头,它是一个回车符。然后是 3。

所以实际上,字符串被视为"aaa\n3"。这就是你得到你所做的输出的原因。

编辑:感谢 Galik,我还要补充一点,我提到的这些规则可能仅适用于字符串文字/c-string。 std::strings 可能是另一种情况,其中字符串的长度是提前知道的。

【讨论】:

  • @Galik 没关系,不过我想知道我哪里弄错了。
  • @Galik 对于来自字符串文字的字符串构造函数来说,这是真的!这在这里很重要。更一般地说,嵌入的 NUL 被正确放置在数组中,并且使用该文字的代码不需要忽略它(例如,指定全长的写入将在那里找到所有数据),只是 ASCIIZ 处理会忽略它.
  • 我确实承认我所说的在技术层面上可能不正确,但出于实际目的,我觉得它是正确的。如果不是,我就删除它。
  • 其实@BWG 我很抱歉。我实际上误读了您的答案,以为您在谈论 std::string 而不是普通的 c-strings.... 我将删除我的评论。
  • 实际上@Fred Larson 有完整的解释这里发生了什么。编译器将\0123 读取为\012(3 位八进制数),后跟3。终止的 null 紧随其后。
【解决方案2】:

\0 是标准的字符串终止符。因此,您可以逐个字符地阅读,也可以避免将 \0 作为 delemeters

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-06-28
    • 2015-10-09
    • 1970-01-01
    • 2016-06-18
    • 1970-01-01
    • 2015-04-20
    • 2010-11-10
    • 2022-07-27
    相关资源
    最近更新 更多