0

这个问题几乎可以归结为“我可以安全地将函数指针转换为具有可转换为这些类型的参数的函数指针吗?”,但如果没有实际示例,这听起来非常可疑。

我做了一个小实用函数来从 DLL 调用某些东西,给定 DLL 名称、函数名称、适当的返回类型以及参数类型和参数。但是,使用此实用程序时可能会出现超出所需内容的额外膨胀。我想知道不明确指定参数类型是否安全。以 Windows APIMessageBoxW为例:

callStdcallDllFunction<int, HWND, PCWSTR, PCWSTR, UINT>(
    L"user32", "MessageBoxW", nullptr, nullptr, nullptr, 0
);

这里我明确指定了返回类型和四种参数类型MessageBoxW。当然,如果从右边开始的参数具有与函数中相同的类型,我不必指定这些。但是,只要首先传递给函数的参数是有效的(这些都是),就可以推断类型吗?

callStdcallDllFunction<int>(L"user32", "MessageBoxW", nullptr, nullptr, nullptr, 0);

在这里,我相信 的结果GetProcAddress将被转换为int(__stdcall *)(std::nullptr_t, std::nullptr_t, std::nullptr_t, int);. 不过,传入的参数仍然适合实际功能。这仍然是定义明确的行为吗,它会一直做我想要的吗?到目前为止,我每次测试它都有效。

当我使用它时,是否可以将返回类型保留为void未使用过的类型?

//return type is void instead of the actual int
callStdcallDllFunction(L"user32", "MessageBoxW", nullptr, nullptr, nullptr, 0);

据我所知,这在我每次尝试时都有效。如果这些确实可以保证工作,我很想能够像这样使用它们,但我真的不知道它们是否总是会,而且我不打算冒险我写的东西是未定义的行为.

确切的代码与问题无关,但您可以在此处找到MessageBox可用于测试的 stdcall 版本(例如版本)。这些和 cdecl 版本之间的唯一区别是在函数签名中添加。__stdcall

4

1 回答 1

1

您必须知道调用约定的确切细节,并且 ABI 曾经能够给出准确的答案。

在某些调用约定中,参数在堆栈上传递。只要参数的大小相同,并且不涉及额外的转换,您就不会面临崩溃的风险。返回值:如果是在栈上返回的,要小心。如果它在寄存器中返回,则无关紧要。

通常具有相同长度的类型不是问题。但要小心更奇特的类型,如成员(函数)指针,例如,它们不一定与 void* 具有相同的大小。

可转换是不够严格的。char 可以转换为 long,但在堆栈上它们占用不同数量的字节,因此这样的函数指针转换可能会导致对堆栈内容的不同解释。

于 2013-05-07T18:52:59.663 回答