奇怪的 C++ std::string 行为......我该如何解决这个问题?

Posted

技术标签:

【中文标题】奇怪的 C++ std::string 行为......我该如何解决这个问题?【英文标题】:Strange C++ std::string behavior... How can I fix this? 【发布时间】:2009-04-28 05:16:26 【问题描述】:

这让我发疯了。我已经研究了 2 个多小时试图弄清楚这一点......

这是我的问题。我正在开发一个与贝叶斯网络一起使用的相当大的程序。这是主要功能:

using namespace std;

int main()
  
    DSL_network net;
    initializeNetwork(net); 
    setEvidence(net);
    net.SetDefaultBNAlgorithm(7);
    net.SetNumberOfSamples(80000);
    cout << "Samples:\t" << net.GetNumberOfSamples() << endl;
    updateEvidence(net);
    //net.WriteFile("test.dsl");
    return(DSL_OKAY);

这一切都很好。当我想打印一个字符串时,问题就来了:

using namespace std;

int main()
  
    //simple string creation
    string a = "test";
    //should print out "test"
    cout << a << endl;
    DSL_network net;
    initializeNetwork(net); 
    setEvidence(net);
    net.SetDefaultBNAlgorithm(7);
    net.SetNumberOfSamples(80000);
    cout << "Samples:\t" << net.GetNumberOfSamples() << endl;
    updateEvidence(net);
    //net.WriteFile("test.dsl");
    return(DSL_OKAY);

这是输出(只是打印字符串 a...):

   ▀ÇΦy♠≈6 ♦

会发生什么?

更新:

int main()
      
        //simple string creation
        string a = "test";
        //should print out "test"
        cout << a << endl;
        return(DSL_OKAY);
    

仍然打印

▀ÇΦy♠≈6 ♦

重大更新: 这是最近的。我创建了一个全新的项目并粘贴了 Neil Butterworth 发布的代码(谢谢顺便说一句)。我运行了代码,它打印正确。然后我将这两个.lib 文件添加到新项目的链接器中(smile.lib 用于 SMILE 库,wsock32.lib 用于套接字。)

我再次尝试了代码,它正确打印了第一个“测试”,然后打印了乱码。这是我链接在一起的一个 .lib 的问题。我自己尝试了每一个,看看它们是否只是冲突,似乎是 Smile.lib 库导致了这个问题。我需要查看他们的文档并找出原因。

有什么想法吗?

感谢大家的帮助

谢谢

【问题讨论】:

这有点含糊(至少在这个时候对我来说)——你是在说:'string a = "test"; cout 是否有任何#includes 也可能包含字符串类? 是的,可能有。这会是个问题吗?我会检查的 “我是一个使用贝叶斯网络的相当大的程序。”哇,我印象深刻,你写了一个有感知力的程序,它知道如何向 SO 发布它自己的问题! 我检查了#includes,没有冲突。 【参考方案1】:

这很奇怪。我总是喜欢将问题分解为最小的情况。下面的程序在你运行时做了什么?

using namespace std;
int main()   
    string a = "test";
    cout << a << endl;
    return 0;

如果这样可行,那么还有其他问题,您需要一次添加一行,直到它失败。然后仔细检查那行非常(“我在打猎兔兔”)。

根据您的编辑,可能使用了不同的字符串类。试试这个:

int main()   
    std::string a = "test";
    std::cout << a << std::endl;
    return 0;

更新:

由于它适用于新项目而不是当前项目,请检查以下内容。

确保您链接的是标准 C++ 运行时。 确保您没有将string 定义为其他内容(其中包括编译器的-Dstring=somethingelse 命令行选项)。 使用std::string检查行为,而不仅仅是string

【讨论】:

这都是与项目相关的......我打开了另一个项目,它工作正常。是否有一些设置是错误的?谢谢 如果您有调试器,请在打印前检查实际变量“a”。它可能不是 std::string。 std:: 版本在可疑项目中做了什么? 您使用的是哪个编译器/IDE。项目是特定于产品的。 两个字符串(正在工作的项目,和顶起一个)显示为 std::basic_string,std::allocator>。我正在使用 VS2005 谢谢 这是个问题吗? .\SocketC.cpp(207) : 警告 C4996: 'strerror' 被宣布弃用【参考方案2】:

也试试这个:

int main()
      
        //simple string creation
        string a = "test";
        const char* cStr = a.c_str();
        //should print out "test"
        cout << cStr << endl;
        return(DSL_OKAY);
    

如果const char* 行没有导致编译器错误,那么我们知道std::str 是一个8 位字符串。如果cout 没有导致编译器错误,那么我们知道cout 是为8 位字符定义的。 (如果程序产生相同的结果,那么我们仍然感到困惑:-

编辑(基于您在下面的评论):我注意到“test”的错误输出为 9 个字符——“▀ÇΦy♠≈6 ♦”。尝试其他“测试”字符串,例如,哦,“retest”或“foo”。我怀疑您的输出通常是原始字符串中字符数的 2x 或 2x+1(“retest”为 12 或 13,“foo”为 6 或 7。)这表明您正在输入 16 位字符串进入一个 8 位缓冲区。不过,我不知道您如何才能通过编译器 - 也许您对 std::string 和/或 cout 的定义有误或过时?

编辑 2:我记得我以前在哪里看到过这个。几年前,我看到了一个问题,即 DOS 控制台窗口破坏了程序的输出。 (我不记得确切的细节,但我认为问题在于 DOS 控制台无法处理 UTF-8 字符集。)如果您在 DOS 窗口中看到此输出(或者,不太可能,如果它是通过system() 传送到另一个程序),然后尝试将其重定向到一个文件,然后用记事本打开该文件。它可能会起作用......

【讨论】:

这是我打印“a”得到的结果:ÿÿÿÿ߀èy÷6 附言。长度始终为15... ▀ÇΦy♠≈6 ♦ 前后有一些空字符【参考方案3】:

检查是否

你有#include&lt;iostream&gt; 和其他相关的标题包括吗? net.GetNumberOfSamples() 具有有效值 AND 你没有混合stringwstring

【讨论】:

是的。假设包含正确的#include。 net.GetNumberofSamples 是问题所在。这将返回一个 int 并打印正常。【参考方案4】:

您是否 100% 认为源代码文件是 ASCII?尝试在一些十六进制编辑器中打开它。

尝试在一个全新的文件中输入(而不是复制/粘贴)代码,看看会发生什么。

如果失败了,那么显然你的 cout 有什么问题。你能告诉我们哪些库链接到可执行文件中吗?也许某些东西会关闭标准输出流或类似的东西。

【讨论】:

【参考方案5】:

我建议您慢慢删除所有#include,直到找到导致问题的那个。

【讨论】:

【参考方案6】:

您可以尝试为字符串类型显式指定 std 命名空间。

我建议您尝试这样做的主要原因是,在某些包含的头文件中可能有一个定义,它将字符串替换为其他一些类或定义。添加命名空间应强制不使用宏。

要检查的另一件事是获取写入文件的源代码的已处理列表(或程序集和源代码列表,如果您想进行一些程序集黑客攻击)并检查它以查看发生了什么.如果不出意外,您可能会在那里找到答案。

【讨论】:

【参考方案7】:

编译并运行以下确切代码;不要添加任何 using 指令。

#include <iostream>
#include <string>

int main() 
    std::string s = "test";
    for ( unsigned int i = 0; i < s.size(); i++ ) 
        std::cout << s[i];
    
    std::cout << "\n";
    std::operator<<( std::cout, s );
    std::cout << "\n";

如果循环打印“test”,则表示字符串正常,问题出在输出中。如果第二个“测试”被破坏,那么问题肯定出在输出处理中。

【讨论】:

感谢您的提示。在我的帖子中查看我的重大更新【参考方案8】:

将 std::string 转换为 char 字符串是否有效。 即:

cout << a << endl;

变成

cout << a.c_str() << endl;

【讨论】:

【参考方案9】:

您似乎很可能正在混合 wchar 和 char,因此在您的主要固定字符被认为是宽的(2 字节/字符)或一些 unicode,并且您的 cout 库认为它们是简单的 1 字节/字符。我会查看与项目链接的库。

不幸的是,我不确定如何解决这个问题。几乎可以肯定,您可以更改项目的某个设置(不幸的是,我面前没有 VS 2005),但您正在寻找诸如 wchar、t_char 或 unicode 之类的东西。

我很好奇如果你使用会发生什么

string a("test");

而不是直接分配。

【讨论】:

【参考方案10】:

是否有可能在同一个项目的另一个文件中的某个位置,operator &lt;&lt; 被重载? 请尝试搜索“operator &lt;&lt;”或“operator&lt;&lt;”。

【讨论】:

【参考方案11】:

建议:

在您的cout &lt;&lt; 之前致电cout.flush,看看您是否得到了奇怪的字符 试试printf

【讨论】:

以上是关于奇怪的 C++ std::string 行为......我该如何解决这个问题?的主要内容,如果未能解决你的问题,请参考以下文章

扣除 string_view 的 std::make_pair 的一些奇怪行为

C++ 字符连接与 std::string 行为。请解释一下

在 C++ 中比较两个 std::string 时的未定义行为 [关闭]

传递给类时 c_str() 和字符串的奇怪行为

Visual C++ 2010 在调试时拒绝显示 std::string 值。显示 <Bad Ptr>

❥关于C++之智能指针