mfccstring中的变量和转换操作符
varargs and conversion operators in MFC CString
在我测试过的所有版本的Visual c++的MFC中,以下代码可以编译并工作;
CString A = "String A", B;
B.Format("The value of A is %s", A);
但是产生警告
C6284, Object passed as _Param_(2) when a string is required in call to
'ATL::CStringT<char,StrTraitMFC<char,ATL::ChTraitsCRT<char> > >::Format'
Actual type: 'class ATL::CStringT<char,class StrTraitMFC<char,class ATL::ChTraitsCRT<char> > >'.
查看CString及其祖先CStringT CSimpleStrT的源代码,同时有一个转换操作符可以有效地转换为char*,如下所示;
operator PCXSTR() const throw()
{
return( m_pszData );
}
还显示数据缓冲区是类中的第一个数据元素,并且在调试器下跟踪执行表明没有调用转换操作符,代码完全基于类布局工作。
虽然原始代码可以很容易地重写以避免上述问题,但它有必要并且可能被未来的MFC更新破坏吗?所涉及的代码库部分主要是第三方的,我宁愿避免在没有充分理由的情况下更改它。
不,你写的代码是坏的。官方说法是,这是未定义行为。不应该将对象传递给可变函数。这些类型的函数没有编译时类型检查(),即:,不是类型安全的),因此编译器不知道它应该调用隐式转换操作符将CString
对象转换为PCXSTR
。必须显式地执行转换,要么使用强制类型转换,要么调用返回指向底层c风格字符串缓冲区的指针的成员函数。
对于所有可变函数都是如此。甚至像printf
这样简单的东西。以下代码是错误的:
std::string str = "world";
printf("Hello, %s", str); // <-- this code is WRONG!
你必须这样写:
std::string str = "world";
printf("Hello, %s", str.c_str());
对于MFC*:
也是一样的CString str = TEXT("world");
CString buffer;
buffer.Format(TEXT("Hello, %s"), static_cast<LPCTSTR>(str));
// alternatively:
// buffer.Format(TEXT("Hello, %s"), str.GetString());
这是在c++中不使用可变函数的一个很好的理由。首选流,它是类型安全的,做正确的事情。
您得到的警告是试图提醒您注意这个问题。尽管可变函数不是类型安全的,但这是一个非常常见的问题,编译器供应商已经投入了大量的精力来尝试解析格式字符串,查找插入,并将这些插入与传递的参数进行匹配。在这种情况下,由于我描述的原因,它发现了一个不匹配,并且发出了警告C6284。
*实际上,在这种情况下,它恰好可以用于CString。这是因为,正如您在调试器中发现的那样,该类是专门设计的,因此它的第一个成员是指向c风格字符串缓冲区的指针。因此,当它以非类型安全的方式按值传递给像printf
这样的可变函数时,printf
看到的唯一东西就是指针,所以当它看到%s
说明符时,它得到了正确的解析。但我不建议依赖这种行为。它仍然是形式上未定义的行为,即使它以特定于实现的方式工作。
微软的文档特别是告诉你通过对char指针执行显式强制转换将CString对象传递给可变函数。
当然,CString的接口不太可能在此时改变,甚至更不可能,因为它会破坏这么多现有的代码。但是你永远不会知道,当你正确地编写代码时,它会使你的意图更清晰。- 我可以将C 17 Capture lambda ConstexPR转换操作符的结果用作函数指针模板非类型参数吗?
- Clang vs GCC vs MSVC模板转换操作符-哪个编译器是正确的
- 模板类型转换操作符=
- 链接隐式转换操作符
- 强制转换操作符函数在g++中可以很好地编译,但在其他编译器中不行.为什么
- 当目标类有多个构造函数时,消除强制转换操作符的歧义
- 删除转换操作符
- 强制转换操作符重载和引用
- 实现没有临时的转换操作符
- 不同的强制转换操作符被不同的编译器调用
- 为什么模板化的用户定义转换操作符能够确定其返回类型?
- const转换操作符
- 调用转换操作符不能用于静态const变量
- 内部编译器错误-开关表达式中的模板化转换操作符
- 强制转换操作符可以是显式的吗?
- 不同的编译器使用不同的强制转换操作符
- 是否需要重载类的强制转换操作符?
- 类型转换操作符重载——Visual studio 2013内部错误
- ' auto x = type{…} '初始化语法和'显式'转换操作符- clang vs gcc
- 是否有方法为任何指针类型定义转换操作符