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

时间:2016-12-24 13:24:42

标签: c++ visual-studio visual-c++ mfc code-analysis

我有这个方法:

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。

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

1 个答案:

答案 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的实现中,尽管我不是我面前有一个编译器。也许你可以证明我错了?)