C++ 在现代C++;应用程序,你应该使用正确的铸造吗?

C++ 在现代C++;应用程序,你应该使用正确的铸造吗?,c++,winapi,visual-c++,C++,Winapi,Visual C++,例如,在整个MSDN文档中可以找到以下铸件: (LPTSTR)&lpMsgBuf 我是否应该费心将其转换为: static_cast<LPTSTR>(&lpMsgBuf); static_cast(&lpMsgBuf); 或者我应该把所有的习惯性C-WES32 Win32部分都放在文档中,并且保存我的代码中更为通用的C++样式/用法吗?< P>MSDN文档和C++标准>p> 我会选择后者。我认为这也是有效C++中讨论的规则之一。您不应该在一个程序中混用两种样式。

例如,在整个MSDN文档中可以找到以下铸件:

(LPTSTR)&lpMsgBuf
我是否应该费心将其转换为:

static_cast<LPTSTR>(&lpMsgBuf);
static_cast(&lpMsgBuf);

<>或者我应该把所有的习惯性C-WES32 Win32部分都放在文档中,并且保存我的代码中更为通用的C++样式/用法吗?

< P>MSDN文档和C++标准>p>
我会选择后者。我认为这也是有效C++中讨论的规则之一。您不应该在一个程序中混用两种样式。

引入新的样式转换是出于一个原因:它们更安全、更具解释性/自评性、更易于查看、更易于搜索

所以使用它们

更具解释性的是,我们的意思是,您不能只是强制转换到某个对象,您必须说明您进行强制转换的原因(我在继承层次结构中进行强制转换(dynamic_cast),我的强制转换是实现定义的,可能不可移植(reinterpret_cast),我正在放弃constness(const_cast),等等)

它们故意又长又丑,以至于演员们会跳到读者面前(并阻止使用过多演员的编程风格)


它们更安全,因为,例如,如果不明确地这样做,你就不能丢弃常量。

你根本不需要强制转换——从外观上看,
lpMsgBuf
是一个指向字符数组的指针(上下文中不清楚它们是ANSI字符还是宽字符),可以直接传递到各种Win32函数

无需获取地址——如果
lpMsgBuf
是一个静态数组(例如
char lpMsgBuf[SIZE]
),则获取其地址是多余的,相当于其第一个元素的地址。如果它是一个指针,那么获取它的地址就会产生一个
char**
(或者如果它很宽,就会产生一个
wchar**
),而这不是您想要传递的内容——如果Win32函数需要一个
LPSTR
(即
char*
),而您将
char**
转换为
char*
,就会产生很多不好的结果。编译器不允许您将
char**
传递给一个需要
char*
的函数而不使用强制转换——使用强制转换使编译器静音是错误的,因为编译器试图告诉您一些重要的事情


在这种情况下,如果不进行强制转换就无法传递想要传递的参数,那么几乎肯定是传递错误了。修复代码,使您不需要强制转换。

如果lpMsgBuf已经是指向t字符串的指针,并且如果API希望指针直接指向t字符串,那么您不应该使用任何强制转换。换句话说,如果数据类型已经正确,那么最好不要使用不必要的强制转换。原因是过度使用强制转换会使您在强制转换关闭编译器的同时对错误视而不见


如果lpMsgBuf已经是一个指向T字符串的指针,并且如果API期望一个指向T字符串的指针,但是API期望该指向指针转换为指向T字符串的指针类型(并且API在使用它时会将其转换回),那么您就做对了

如果lpMsgBuf是指向其他类型(正确类型)的指针,并且API需要指向您的类型的指针,但API需要这些角色扮演游戏,那么您做得对

如果lpMsgBuf是指向T-string的指针,并且如果API需要指向T-string的指针,那么通过使用&运算符,您正在构造指向API不需要的T-string指针的指针,通过使用强制转换,您告诉编译器将指向指针的指针转换为指向T字符串的类型指针,即使该值仍然指向指针。因此,您成功地关闭了编译器,但仍然向您或您的客户提供垃圾结果

因此,如果没有更多关于哪个MSDN页面告诉您创建指向指针的指针并为哪个API玩铸造游戏的详细信息,我们无法猜测您是否做得对,或者您是否误读了MSDN,或者MSDN是否告诉您编写错误的代码


现在,如果强制转换实际上是正确的,那么使用哪种语法的选择取决于程序其余部分中的样式。

而不是将我的代码添加到旧样式强制转换或新样式强制转换中,我将利用C++的运算符重载来添加采用适当类型参数的WindowsAPI函数的内联重载版本。(只要这是为新开发人员编写的文档,希望不会太混乱。)

例如,
FormatMessage
的第五个参数通常是一个
LPTSTR
,但如果传递
FORMAT\u MESSAGE\u ALLOCATE\u BUFFER
标志,则第五个参数是指向LPTSTR的指针。所以我要定义一个如下的函数:

inline DWORD WINAPI FormatMessage(
  __in      DWORD dwFlags,
  __in_opt  LPCVOID lpSource,
  __in      DWORD dwMessageId,
  __in      DWORD dwLanguageId,
  __out     LPTSTR *lpBuffer,
  __in      DWORD nSize,
  __in_opt  va_list *Arguments
) {
    assert(dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER);
    return FormatMessage(dwFlags, lpSource, dwMessageId, dwLanguageId, static_cast<LPTSTR>(&lpBuffer), nSize, Arguments);
}
内联DWORD WINAPI格式消息(
__在德沃德·德弗拉格,
__在opt LPCVOID lpSource中,
__在DWORD dwMessageId中,
__在DWORD dwLanguageId中,
__输出LPTSTR*lpBuffer,
__在德沃德·恩西泽,
__in_opt va_list*参数
) {
断言(dwFlags&格式化消息分配缓冲区);
返回FormatMessage(dwFlags、lpSource、dwMessageId、dwLanguageId、static_cast(&lpBuffer)、nSize、参数);
}

代码> ,MSDN Win32示例代码大部分与C和C++兼容。使用普通的旧C编写windows程序是完全允许的(在某个时间点上也是标准做法)


<>因为C++中的caskcts不可用,修改示例以利用它们需要两个示例代码的副本。因为C代码和C++一样工作,所以只需要把旧的样式放进去就更容易了。当我们打字的时候,一个答案已经被接受了,他说这个很有可能充满bug的代码应该仍然很有可能充满bug。真是浪费我们的努力。不幸的是,Windows API有时确实需要查看