C++ 为什么std::ends会导致字符串比较失败?

C++ 为什么std::ends会导致字符串比较失败?,c++,stl,boost,C++,Stl,Boost,我昨天花了大约4个小时试图在代码中修复这个问题。我将问题简化为下面的例子 其思想是将字符串存储在以std::ends结尾的stringstream中,然后稍后检索它并将其与原始字符串进行比较 #include <sstream> #include <iostream> #include <string> int main( int argc, char** argv ) { const std::string HELLO( "hello" );

我昨天花了大约4个小时试图在代码中修复这个问题。我将问题简化为下面的例子

其思想是将字符串存储在以std::ends结尾的stringstream中,然后稍后检索它并将其与原始字符串进行比较

#include <sstream> #include <iostream> #include <string> int main( int argc, char** argv ) { const std::string HELLO( "hello" ); std::stringstream testStream; testStream << HELLO << std::ends; std::string hi = testStream.str(); if( HELLO == hi ) { std::cout << HELLO << "==" << hi << std::endl; } return 0; } #包括 #包括 #包括 int main(int argc,字符**argv) { 常量std::字符串HELLO(“HELLO”); std::stringstream testStream;
testStream
std::ends
在流中插入一个空字符。将内容获取为
std::string
将保留该空字符,并在相应位置使用该空字符创建一个字符串

因此,std::string确实可以包含嵌入的空字符。以下std::string内容不同:

ABC
ABC\0
二进制零不是空白。但它也是不可打印的,所以你看不到它(除非你的终端特别显示它)

当您传递
.C_str()
时,使用
strcmp
进行比较将把
std::string
的内容解释为C字符串

嗯,第一个
\0
(终止空字符)之前的字符是ABC,所以我认为字符串是ABC

因此,它不会看到上述两者之间的任何区别。您可能有这个问题:

std::stringstream s;
s << "hello";
s.seekp(0);
s << "b";
assert(s.str() == "b"); // will fail!
std::strings;

传统上,C和C++中的字符串用null(ASCII 0)字符终止,但是结果是 STD::String 并不真正需要这个东西。不管怎样,我们逐个地逐个逐个地查看代码,我们看到一些有趣的事情:

int main( int argc, char** argv )
{
字符串文本
“hello”
是一个传统的以零结尾的字符串常量。我们将整个字符串复制到
std::string
hello中

    const std::string HELLO( "hello" );

    std::stringstream testStream;
现在,我们将
字符串
HELLO(包括尾随的0)放入
,然后是第二个空值,该空值通过调用
std::ends
放在那里

    testStream << HELLO << std::ends;
然后,我们使用
std::string
类上的
操作符==
比较这两个字符串比较
字符串
对象的长度-包括尾随空字符的数量。请注意,
std::string
类不要求基础字符数组以尾随空字符结尾-换句话说,它允许字符串包含空字符,因此两个尾随空字符中的第一个是tr作为字符串的一部分创建
hi

由于这两个字符串的尾随空数不同,因此比较失败

    if( HELLO == hi )
    {
        std::cout << HELLO << "==" << hi << std::endl;
    }

    return 0;
}
if(HELLO==hi)
{

std::cout您正在使用std::ends向HELLO添加空字符。当您使用str()初始化hi时,您正在删除空字符。字符串不同。strcmp不比较std::strings,而是比较char*(它是一个C函数)。

std::ends添加空终止符(char)“\0”。您可以将其与不推荐使用的strstream类一起使用,以添加空终止符


stringstream不需要它,事实上它把事情搞砸了,因为空终止符对stringstream来说不是“结束字符串的特殊空终止符”,对stringstream来说只是另一个字符,第零个字符。stringstream只是添加它,这增加了字符数(在您的例子中)到7,并与“你好”进行比较失败。

我认为比较字符串的一个好方法是使用
std::find
方法。不要混合使用C方法和
std::string方法。

一定很喜欢StackOverflow-在我写了一个两行答案的时候,有人写了《战争与和平》:-),而且看来我在str()方面是错的作品。为我回到绘图板上!;)那是一个很棒的博客!谢谢你的链接!(尽管它主要是为20世纪的男孩发布的):pOkay,我理解这背后的机制,但我不喜欢语义。似乎我有两个选择:不要使用std::ends并冒着垃圾数据的风险,或者使用它并添加自定义代码以消除多余的空字符。您应该尝试设计代码,以便了解字符串的期望值-例如,如果在从网络设备读取字符串时,它们可能不是以null结尾的,但这取决于您使用的API,但如果您在应用程序中传递字符串,则它们可能是以null结尾的。不要出现您不知道数据中包含什么的情况。为什么要使用ends?这仅在您构建应用程序时使用p a null从原始数据终止C样式字符串。在这里,在您的例子中,它显然不合适。您已经有一个C++字符串。您不需要用<代码> STRSTROR> <代码>。<代码:Str::CyString()/Cyto>无论字符串是如何构建的,都总是正确的NUL终止。
    std::string hi = testStream.str();
    if( HELLO == hi )
    {
        std::cout << HELLO << "==" << hi << std::endl;
    }

    return 0;
}