直接在 swscanf 中使用 CString 的奇怪行为
Posted
技术标签:
【中文标题】直接在 swscanf 中使用 CString 的奇怪行为【英文标题】:Strange behavior using CString in swscanf directly 【发布时间】:2021-09-23 07:39:13 【问题描述】:我对@987654321@ 和STL
的set
有一个问题。CString
和 STL
一起使用看起来有点奇怪,但我试着好奇。
我的代码如下:
#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 的奇怪行为的主要内容,如果未能解决你的问题,请参考以下文章