直接在 swscanf 中使用 CString 的奇怪行为

Posted

技术标签:

【中文标题】直接在 swscanf 中使用 CString 的奇怪行为【英文标题】:Strange behavior using CString in swscanf directly 【发布时间】:2021-09-23 07:39:13 【问题描述】:

我对@9​​87654321@ 和STLset 有一个问题。CStringSTL 一起使用看起来有点奇怪,但我试着好奇。 我的代码如下:

#include "stdafx.h"
#include <iostream>
#include <set>
#include <atlstr.h>

using namespace std;

int _tmain(int argc, _TCHAR* argv[])

    wchar_t line[1024] = 0;
    FILE * pFile = _wfopen(L"F:\\test.txt", L"rt");

    set<CString> cstr_set;

    while (fgetws(line, 1024, pFile))
    
        CString cstr;
        swscanf(line, L"%s\n", cstr);
        cstr_set.insert(cstr);
    

    fclose(pFile);
    cout << "count" << cstr_set.size();
    return 0;

test.txt的内容是:

13245  
123  
2344  
45  

循环结束后,cstr_set 只包含一个值。 它就像cstr 是静态变量或常量变量一样工作。 有什么问题?

【问题讨论】:

我很确定 swscanf 不知道如何填充 CString 并且随之而来的是各种有趣的内存损坏。 那为什么还要继续使用局部变量cstr呢?如果我一步一步在调试模式下运行它,局部变量'cstr'的缓冲区在每个循环中使用相同的内存,因此它似乎没有添加要设置的值。 @secuman:未定义行为未定义。从字面上看,任何事情都可能发生。 CString 可以与 stl set 一起使用吗? -- 你问了这个问题,但你展示的代码不仅仅是使用 @987654334 在集合中设置值@ 类型。一个非常简单的main 程序怎么样,其中字符串在一个数组中,而不是读取已经指出的内容的狡猾的文件? @secuman 好吧,标题的答案是“是的,CString 可以在 std::set 中使用”。问题是你通过使用swscanf 引入未定义的行为搞砸了事情。创建一个简单的数组,即const wchar_t* test[] = L"12345", L"123", L"2344", L"45" ; -- 编写一个循环,将test[i] 分配给cstr,您将看到std::set 正常工作。为什么您最初不将其作为测试,这是另一回事。 【参考方案1】:

CString 是一种 Microsoft 实现,将字符数组包装到 C++ 对象中以允许更简单的处理。

但是swscanf 是一个很好的老式 C 函数,它对 CString 是什么一无所知:它只希望它的参数足够大以接受解码后的值。它永远不应该直接传递一个 CString。

正确的方法是:

...
#include <cstring>
...
while (fgetws(line, 1024, pFile))

    line[wcscspn(line, L"\n")] = 0;  // remove an optional end of line
    CString cstr(line);
    cstr_set.insert(cstr);

...

【讨论】:

我想知道为什么在swscanf中直接使用CString会出现这个问题。 @secuman:因为 scanf 中的%s 需要一个足够大的 char 数组来保存解码后的字符串,而 CString 不是那样的。所以你只需调用 Undefined Behaviour... 你是对的。当我将cstr.GetBufferSetLength(1024); 添加到swscanf 上面时,问题就解决了。

以上是关于直接在 swscanf 中使用 CString 的奇怪行为的主要内容,如果未能解决你的问题,请参考以下文章

C++里sscanf()与swscanf()的使用

C++里sscanf()与swscanf()的使用

swscanf_s和sscanf_s的使用

sscanf函数

swscanf反向格式化字符串为相应的数据

swscanf反向格式化字符串为相应的数据