C++ 为什么在使用可变函数时必须将CString转换为LPCSTR?

C++ 为什么在使用可变函数时必须将CString转换为LPCSTR?,c++,mfc,C++,Mfc,是否有人知道该代码不正确的原因,根据: 的Microsoft文档说明: …当您将字符串作为可选参数传递时,必须将其显式转换为LPCTSTR 我总是用“错误”的方式(没有LPCSTR演员阵容),我从来没有遇到过问题 我在这里遗漏了什么吗?因为Format函数内部没有进行转换,就像您在printf()中指定参数时没有进行转换一样。 如果您编写printf(“%d”,a)

是否有人知道该代码不正确的原因,根据:

的Microsoft文档说明:

…当您将字符串作为可选参数传递时,必须将其显式转换为LPCTSTR

我总是用“错误”的方式(没有LPCSTR演员阵容),我从来没有遇到过问题


我在这里遗漏了什么吗?

因为Format函数内部没有进行转换,就像您在
printf()中指定参数时没有进行转换一样。

如果您编写
printf(“%d”,a)%d
已经告诉了
a
是什么数据类型,因此没有对
a
进行转换

为了确保
CString
转换为
LPCSTR
,即
%s
,您需要在返回
LPCSTR
CString
上调用运算符的参数。在CString的更高版本中,字符串被存储,这样当您在没有强制转换的情况下写入时,它仍将作为LPCSTR打印,但为了确保更好地执行强制转换

或者换一种方式:当变量函数遍历参数时,如果格式说明符与您得到的参数不匹配,它将使用格式说明符来了解参数的大小。由于CString没有格式说明符,所以需要将CString转换为LPCSTR


顺便说一句,您应该在C++

中使用
static\u cast(First),static\u cast(Last)
,转换到LPCSTR调用cast操作符
操作符LPCSTR()
(应该是
操作符const char*()

不调用LPCSTR意味着传递整个CString对象,然后盲目地使用底层结构的前32位或64位作为char指针

总而言之:
LPCSTR(str)
正在调用一个方法来确保正确的行为,而
str
则是盲位旋转。

我认为(很抱歉,我现在没有可用的MFC来检查)强制转换仅仅是出于效率的原因,以避免在参数类型未知时MFC必须执行的无用的临时复制(CString在修改时被延迟复制)

诀窍在于,CString内存分配在
之前为缓冲区(TCHAR*)以外的一些基本数据(如引用计数器)保留空间

然后,当您将CString by值传递给变量函数时,它会“看到”缓冲区(指针)
强制转换只“提取”缓冲区,而不调用复制构造函数。

因为如果使用子类CString参数,它会中断。

这就是实际发生的情况。如果将CString对象作为可变参数,编译器实际上会将CString对象的前32位推送到堆栈上。这在CStri的情况下有效ng,因为CString类的设计方式是,任何CString对象的32位都是指向实际字符串的指针。@MichaelWalz:您的意思是,您对代码未定义的行为感到满意,这取决于
CString
的实现细节,该细节可能会改变,也可能不会改变,因为在您的特定情况下这似乎很有效。现在你的问题是,你为什么要使用cast?答案很简单,以避免未定义的行为。@DavidRodríguez dribeas,我没有说我很高兴,我只是说了实际发生的情况。但是如果CString类的布局发生变化,使用cast肯定可以节省时间。@MichaelWalz你有可变参数的来源吗nts仅将前32/64位推到调用堆栈上?@MichaelWalz没什么大不了的,但我认为我已经将结构直接传递到变量中,如果在调用时所有参数都适合32/64位,这是不可能的。关于这一点的有趣链接是和。实际上,在传递此类对象时,不会创建临时CString对象作为可变参数。请参阅我在上一个答案中的备注。@MichaelWalz:我在重新思考:应该有一个复制构造函数的调用(参数通过值传递),但由于“修改时复制”,因此没有缓冲区复制。仅供参考:当您不使用强制转换时,不会调用复制构造函数。当您使用强制转换时,会调用强制转换运算符,但不会调用复制构造函数。请参阅上面对Jeffery Thomas回答的注释。对于Microsoft编译器,即使您将CString子类化,但如果CString包含虚拟函数然后你会得到垃圾,因为在这种情况下,前4个字节不是指向字符串的指针,而是指向虚拟函数表的指针。这就解释得很清楚了!不幸的是,我所有的dervied CString类都使用虚拟析构函数进行清理。我不确定是否可以使用非虚拟析构函数。我不使用CString*ptr=new CMyStringEx(),但另一个程序员可能有。
CString First( "John" );
CString Last( "Doe" );

CString Name;

Name.Format( "%s %s", First, Last ); // Name may be garbage text

Name.Format( "%s %s", (LPCSTR)First, (LPCSTR)Last ); // this is the correct way