如何解决使用FARPROC调用GetProcAddress周围的C4191警告?

时间:2010-11-16 07:43:56

标签: c++ winapi casting function-pointers compiler-warnings

最近我尝试使用/Wall Visual C++ option启用所有警告,并发现以下代码:

typedef BOOL ( WINAPI * TIsWow64ProcessFunction )( HANDLE, BOOL* );
TIsWow64ProcessFunction isWow64ProcessFunction = reinterpret_cast<TIsWow64ProcessFunction> (
    ::GetProcAddress( kernel32DllHandle, "IsWow64Process" ) );

产生了C4191

warning C4191: 'reinterpret_cast' : unsafe conversion from 'FARPROC' to 'TIsWow64ProcessFunction'
Calling this function through the result pointer may cause your program to fail

如果我使用C风格的强制转换,则会出现相同的警告,但现在它会提到“type cast”而不是“reinterpret_cast”。

对于我调用GetProcAddress()并将其返回值转换为某个可用函数指针的任何情况,都会重复相同的警告。

如何解决这些警告?我是否需要对代码进行更改?

4 个答案:

答案 0 :(得分:7)

您正在使用args将FARPROC(没有args的函数指针)转换为函数指针。通常,这是一个非常愚蠢的事情,可能会导致堆栈损坏。

现在事实证明GetProcAddress()并没有真正返回FARPROC并且你确实知道你正在做什么 - 但编译器并不知道这一点,并且它感到有必要警告你。

您可以使其静音的唯一方法是使用#pragma或编译器开关来关闭警告。这是丑陋和混乱,但这是Windows编程为您服务。 : - )

答案 1 :(得分:6)

正如其他答案已经提到的那样,这是一个有用的警告。 Normally, this type of coercion would be a serious bug hiding in your application

因此,您可能不希望使用编译器开关全局禁用它。然而,您仍然需要调用GetProcAddress,并且您希望您的构建能够在没有警告的情况下进行干净的编译。

您有两个不错的选择:

  1. 使用特定于MSVC的编译指示抑制每个警告。在恶意演员阵容正上方的新行中添加以下代码:

    #pragma warning(suppress: 4191)
    

    这会抑制下一行代码 的警告,确保它不会被全局抑制,如果你试图在代码库中的其他地方做一些愚蠢的事情,你仍然会收到警告。当然,每次使用GetProcAddress时都需要添加它,这是一种痛苦。更糟糕的是,它是一个不可移植的,特定于MSVC的扩展,可以使您的代码更加清晰。

    所以,或者......

  2. 您可以通过明确地将GetProcAddress FARPROC的结果投射到void* 来消除警告,然后将void*转换为特定的函数指针类型。例如:

    typedef BOOL ( __stdcall *TIsWow64ProcessFunction )( HANDLE, BOOL* );
    
    TIsWow64ProcessFunction isWow64ProcessFunction =
        reinterpret_cast<TIsWow64ProcessFunction>(
           reinterpret_cast<void*>(
           ::GetProcAddress(hInstance, "IsWow64Process")));
    

    这种方法可以与其他编译器一起使用,稍微不那么难看,并且可以说在语义上更有意义。

答案 2 :(得分:2)

基本上编译器不能保证函数是合适的类型,因此调用结果指针是不安全的。但是,在VS程序中,您不必显式链接或加载Windows .dll,它们将为您加载,并且Windows标头中的任何函数始终可供使用。

答案 3 :(得分:1)

当我经常使用这种东西时,我也被这些警告所困扰。我喜欢@Cody Gray的答案,因为它仅在使用时抑制警告,但不会过滤掉其他可能有效的警告。

我做了一个简单的function_cast助手,使它更像c ++:

template<typename Result, typename Original>
Result function_cast(Original fptr)
{
  return reinterpret_cast<Result>(reinterpret_cast<void *>(fptr));
}

OP的代码变为:

auto isWow64ProcessFunction = function_cast<TIsWow64ProcessFunction>(::GetProcAddress( kernel32DllHandle, "IsWow64Process" ) );