我有这个方法:
void CMeetingScheduleAssistantDlg::RestartProgram()
{
RESTART_THIS_MFC_APP;
}
它按照定义调用宏:
#define RESTART_THIS_MFC_APP \
{ \
HWND _hWndMain = AfxGetApp()->m_pMainWnd->GetSafeHwnd(); \
DWORD _dwProcessID = (DWORD)_getpid(); \
TCHAR _cFilespec[_MAX_PATH + 1]; \
if (::GetModuleFileName(AfxGetInstanceHandle(), _cFilespec,_MAX_PATH) == 0) \
AfxMessageBox(_T("ERROR: Could not obtain full filespec of this application to restart it."), MB_OK|MB_ICONSTOP); \
else \
{ \
CString strAppFilespec(_cFilespec); \
; \
LPTSTR lpszFilename = ::PathFindFileName(_cFilespec); \
_tcscpy_s(lpszFilename,_MAX_PATH - (lpszFilename - _cFilespec),_T("AppRestarter.exe") ); \
; \
CString strAppRestarterFilespec(_cFilespec); \
; \
CString strCmdLine ; \
strCmdLine.Format(_T("%ld %ld \"%s\""),_hWndMain,_dwProcessID,(LPCTSTR)strAppFilespec); \
; \
HINSTANCE hProcess = ::ShellExecute(NULL,_T("open"),(LPCTSTR)strAppRestarterFilespec, \
(LPCTSTR)strCmdLine,_T(".\\"), SW_HIDE); \
if ( (DWORD)(DWORD_PTR)hProcess <= 32) \
AfxMessageBox(_T("ERROR: Could not run application restarter."), MB_OK|MB_ICONSTOP); \
} \
}
以上是提供给我的第三方宏,它与应用程序重新启动程序可执行文件一起使用。原作者不再可用。
应用程序构建并且它正常运行。但是我收到了代码分析错误:
警告C6273:当整数为时,非整数作为 Param (2)传递 要求打电话给 &#39; ATL :: CStringT&gt;
::格式&#39;实际类型:&#39; struct HWND__ *&#39;:如果传递指针值,则应使用%p。
_hWndMain
属于HWND
类型,但我不能使用%p
作为格式代码。如果我这样做,那么应用程序重启器失败并告诉我它希望这个参数是数字。
所以你可以看到我恢复使用我认为是正确的%ld。
通过更改我的代码可以抑制此警告吗?或者这只是我必须忍受的误报?
答案 0 :(得分:2)
不是误报;警告是正确的,并发现了一个错误。 %ld
不对,因为指针不是整数。语言规范很明显,因此%ld
是错误的,因为它指示函数将指针值解释为长整数。这可能出错的众多方法之一是针对64位处理器,其中指针为64位宽但整数(包括long
s)仅为32位宽。 %ld
将切断高位。
使用CString<T>::Format
,您必须使用与printf
相同的规则,这就是警告告诉您需要使用%p
传递指针值的原因。将HWND
视为指针的原因是因为这是在Windows标头中定义类型的方式。它在技术上不是一个指针,只是一个不透明的值,但指针语义通常是合适的,可以避免错误。
您说使用%p
不是一个选项,因为您收到参数不是数字的错误。我猜这是因为%p
导致值以CString<T>::Format
认为适合指针值的某种格式打印,可能是十六进制的,甚至可能是0x
前缀,但是您传递格式化字符串的函数并不期望这样。
因此,在将HWND
值与%ld
一起使用之前,您需要将size_t
值明确解释为数值。这不仅会使警告静音,而且会为您提供正确的语义。但是你需要仔细挑选你将用它来代表它的类型。您的第一直觉可能是intptr_t
,但标准不能保证这与指针具有相同的宽度。它将在Windows 32位和64位上“工作”,但在技术上无效。相反,为了安全起见,请选择uintptr_t
或%Id
,具体取决于您是否需要地址的有符号或无符号表示。对于格式字符串,请使用%Ix
,%IX
或%Id
。从当前代码的外观来看,您可能需要strCmdLine.Format(_T("%Id %ld \"%s\""),
reinterpret_cast<intptr_t>(_hWndMain),
_dwProcessID,
static_cast<LPCTSTR>(strAppFilespec));
。您可能还需要明确指出字段的大小,具体取决于消费者期望的格式。
<inttypes.h>
您需要确保已包含%I
。
(请注意,{{1}}格式说明符是Microsoft发明的,因此不可移植。在其他编译器上,您会use the standard macros from inttypes.h
。我不认为这些存在于Microsoft的实现中,尽管我不是我面前有一个编译器。也许你可以证明我错了?)