在将应用程序从VisualStudio 2005迁移到VisualStudio 2015时,我们在某些代码中发现了一种不同的行为,当使用VS2015构建该代码时,它会连接CString实例。 所以,我已经创建了一个简单的Win32控制台应用程序来演示这个问题。
控制台应用程序(使用MFC作为共享dll和Unicode charachter集)执行这个简单的功能:
void f()
{
CString x( '\0' );
CString r( 'a' );
r += x;
CString rr( 'a' );
rr = rr + x;
int rSize = r.GetLength();
int rrSize = rr.GetLength();
assert( rSize == rrSize ); // This assert fires when compiled and run
// under Visual Studio 2015!
}
它表明,当一个CString包含' \ 0' char被连接到另一个CString实例,使用' + ='或使用' +'导致不同的结果!
当' + ='用于计算结果的大小计算所有字符直到第一个' \ 0' ...因此最终大小为1!
相反,当运营商' +'使用结果CString size为2,即连接实例的大小总和!
在VisualStudio 2005中,结果大小始终是连接实例大小的总和!
几周前,我filed a bug给了微软,但直到现在我还没有回复这些家伙。我的问题:
1.有人偶然发现了MCF库中的这个错误吗?
你是如何解决这个错误的?我们正在考虑禁止使用+ =运算符或者用自定义类替换CString类,但所有这些对我而言似乎都是一个"侵入性的。
答案 0 :(得分:6)
CStringT Class的文档包含以下神秘声明:
坦率地说,我真的不知道该怎么做最后一句话。我把它作为一个警告,在嵌入空字符时要小心。无论如何,合同保证在这样做时仍应保留。虽然可以创建包含嵌入空字符的CStringT实例,但我们建议不要使用它。 在包含嵌入空字符的CStringT对象上调用方法和运算符会产生意外结果。
<强>分析:强>
但CStringT::operator+=显然不是这种情况。在问题的示例代码中,operator+=
的实现调用
CSimpleStringT& operator+=( const CSimpleStringT& strSrc )
重载,通过调用
修改当前实例void Append( const CSimpleStringT& strSrc )
反过来调用
void Append( PCXSTR pszSrc, int nLength )
传递显式长度参数。这应该足以处理带有嵌入空字符的C风格字符串。奇怪的是,然后实现开始通过调用StringLengthN(pszSrc, nLength)
(实现为对wcsnlen的调用)来猜测输入,以重新计算 pszSrc 的长度。这将为示例代码中的CStringT
实例 x 返回0。
<强>结果:强>
对我而言,这似乎是实施中的一个错误。顺便提一下,如果您将参数反转为operator+=
(即x += r;
与r += x;
),则结果是一个长度为2的字符串,如预期的那样。
解决:强>
唯一干净的解决方案是让微软承认错误,并提供修复程序。但是,我不会屏住呼吸,因为微软通常不会发布错误修复,如果它们改变了发货产品的行为。
如果您无法说服Microsoft修复该错误,那么您唯一的另一个选择就是不要将操作符用于不受欢迎的行为。一种方法是使用另一个字符串类。一个完善的替代品是std::wstring,您可以在必要时将其转换为CStringW
(CStringW cstr(s.c_str(), s.length());
)。
<小时/> 更新(2016-09-13):
OP向微软提出defect report,他们承认了这个错误。实现了一个错误修复,但“它将不会出现在库的下一个主要版本(可能不一定在当前[2016-03-31] Visual Studio vNext中发布)”。