警告 C6273:当需要整数时,非整数作为 _Param_(2) 传递

warning C6273: Non-integer passed as _Param_(2) when an integer is required

我有这个方法:

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); \
        } \
    }

以上是提供给我的第三方宏,可与应用程序重启器可执行文件一起使用。原作者不在了

应用程序已构建并正常运行。但是我收到代码分析错误:

warning C6273: Non-integer passed as Param(2) when an integer is required in call to 'ATL::CStringT >

::Format' Actual type: 'struct HWND__ *': if a pointer value is being passed, %p should be used.

_hWndMain 确实是 HWND 类型,但我不能使用 %p 作为格式代码。如果我这样做,那么应用程序重启器会失败并告诉我它希望此参数为数字。

正如您所见,我恢复使用 %ld,我认为这是正确的。

是否可以通过更改我的代码来抑制此警告?或者这只是我必须忍受的误报?

不是误报;警告是正确的,并发现了一个错误。 %ld 不对,因为指针不是整数。语言规范在这个事实上很清楚,所以 %ld 是错误的,因为它指示函数将指针值解释为长整数。这可能出错的多种方式之一是针对 64 位处理器,其中指针是 64 位宽但整数(包括 longs,只有 32 位宽)。 %ld 将砍掉高位。

使用 CString<T>::Format 时,您必须按照与 printf 相同的规则进行游戏,这就是警告告诉您需要使用 %p 来传递指针值的原因。 HWND 被认为是指针的原因是因为这是在 Windows headers 中定义类型的方式。它在技术上不是指针,只是一个不透明的值,但指针语义通常是合适的并且避免了错误。

你说使用 %p 不是一个选项,因为你得到一个参数不是数字的错误。我猜那是因为 %p 导致值以 CString<T>::Format 认为适合指针值的某种格式打印,可能是十六进制的,甚至可能是 0x前缀,但是您将该格式化字符串传递给的函数并不期望这样。

因此,在与 %ld 一起使用之前,您需要明确地将 HWND 值解释为数值。这不仅会消除警告,还会为您提供正确的语义。但是您需要仔细选择您将使用哪种类型来表示它。您的第一直觉可能是 size_t,但标准并不能保证这与指针具有相同的宽度。它将在 Windows 32 位和 64 位上 "work",但在技术上无效。相反,为了安全起见,更喜欢 intptr_tuintptr_t,具体取决于您想要地址的有符号表示还是无符号表示。对于格式字符串,使用 %Id%Ix%IX。从当前代码的外观来看,您可能需要 %Id。您可能还需要明确指出字段的大小,具体取决于消费者期望的格式。

strCmdLine.Format(_T("%Id %ld \"%s\""),
                  reinterpret_cast<intptr_t>(_hWndMain),
                  _dwProcessID,
                  static_cast<LPCTSTR>(strAppFilespec));

您需要确保包含 <inttypes.h>

(请注意,%I 格式说明符是 Microsoft 的发明,因此不可移植。在其他编译器上,您会 use the standard macros from inttypes.h。我认为 Microsoft 的实现中不存在这些,尽管我我面前没有编译器。也许你能证明我是错的?)