You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

cl.exe 64位与32位编译报错差异及修复方案咨询

问题:32位MSVC编译Mock代码失败,64位正常运行

以下是源代码:

#include <functional>
#include <minwindef.h>
#include <winerror.h>
#include <libloaderapi.h>
#include <winreg.h>

namespace ffmock
{

/**
 * @brief Primary template
 */
template<typename T>
struct function_traits;

/**
 * @brief Template specialization for APIs
 */
template<typename RetType_t, typename... Args_t>
struct function_traits<RetType_t(Args_t...)>
{
    using Ret_t = RetType_t;
    using Sig_t = Ret_t(Args_t...);
    using Ptr_t = Ret_t(*)(Args_t...);
    using Api_t = std::function<Sig_t>;
};

template<typename RetType_t, typename API_t, RetType_t RetValue, DWORD Error2Set = NO_ERROR>
class
Mock
{
protected:

    using Traits_t = function_traits<API_t>;
    using Ret_t = typename Traits_t::Ret_t;
    using Ptr_t = typename Traits_t::Ptr_t;
    using Api_t = typename Traits_t::Api_t;
    using Mock_t = Mock;

    Mock(HMODULE Module, const char* ApiName);
 
    template<typename... Args_t>
    Ret_t operator()(Args_t&... Args);
};

} // namespace ffmock

#pragma warning(disable:4273) // inconsistent dll linkage

namespace Mocks
{

class FFRegCloseKey
    : public ::ffmock::Mock<LSTATUS, decltype(::RegCloseKey), ERROR_INVALID_HANDLE>
{
    friend
    FFMOCK_IMPORT
    LSTATUS
    APIENTRY
    ::RegCloseKey(
        _In_ HKEY Key
        );

    FFRegCloseKey(HMODULE Module) : Mock_t(Module, "RegCloseKey")
    {
    }
};

} // namespace Mocks

extern "C"    
FFMOCK_IMPORT
LSTATUS
APIENTRY
RegCloseKey(HKEY Key)
{
    static Mocks::FFRegCloseKey mock(LoadLibraryW(L"advapi32.dll"));
    return mock(Key);
}

64位编译输出:

Executing task: C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools/VC/Tools/MSVC/14.38.33130/bin/Hostx64/x64/cl.exe /nologo /Fodemo/bin/x64/ /std:c++17 /EHsc /D_DEBUG /D_AMD64_ /DWIN64 /D_UNICODE /DUNICODE /D_CONSOLE /DFFMOCK_IMPORT=__declspec(dllexport) /c C:\Play\ffmock\demo\tst\Test.cpp

Test.cpp * Press any key to close the terminal.

32位编译错误输出:

Executing task: C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools/VC/Tools/MSVC/14.38.33130/bin/Hostx86/x86/cl.exe /nologo /Fodemo/bin/x64/ /std:c++17 /EHsc /D_DEBUG /D_X86_ /DWIN32 /D_UNICODE /DUNICODE /D_CONSOLE /DFFMOCK_IMPORT=__declspec(dllexport) /c C:\Play\ffmock\demo\tst\Test.cpp

Test.cpp C:\Play\ffmock\demo\tst\Test.cpp(42): error C2027: use of undefined type 'ffmock::function_traits<API_t>'
with
[
API_t=LSTATUS (HKEY)
] C:\Play\ffmock\demo\tst\Test.cpp(41): note: see declaration of 'ffmock::function_traits<API_t>'

with
[
API_t=LSTATUS (HKEY)
] C:\Play\ffmock\demo\tst\Test.cpp(42): note: the template instantiation context (the oldest one first) is
C:\Play\ffmock\demo\tst\Test.cpp(64): note: see reference to class template instantiation 'ffmock::Mock<LSTATUS,LSTATUS (HKEY),6,0>' being compiled C:\Play\ffmock\demo\tst\Test.cpp(42): error C2061: syntax error: identifier 'Ret_t' C:\Play\ffmock\demo\tst\Test.cpp(43): error C2027: use of undefined type 'ffmock::function_traits<API_t>'
with
[
API_t=LSTATUS (HKEY)
] C:\Play\ffmock\demo\tst\Test.cpp(41): note: see declaration of 'ffmock::function_traits<API_t>'

with
[
API_t=LSTATUS (HKEY)
] C:\Play\ffmock\demo\tst\Test.cpp(43): error C2061: syntax error: identifier 'Ptr_t' C:\Play\ffmock\demo\tst\Test.cpp(44): error C2027: use of undefined type 'ffmock::function_traits<API_t>'
with
[
API_t=LSTATUS (HKEY)
] C:\Play\ffmock\demo\tst\Test.cpp(41): note: see declaration of 'ffmock::function_traits<API_t>'

with
[
API_t=LSTATUS (HKEY)
] C:\Play\ffmock\demo\tst\Test.cpp(44): error C2061: syntax error: identifier 'Api_t' C:\Play\ffmock\demo\tst\Test.cpp(50): error C2143: syntax error: missing ';' before '('
C:\Play\ffmock\demo\tst\Test.cpp(50): error C2238: unexpected token(s) preceding ';' C:\Play\ffmock\demo\tst\Test.cpp(50): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int C:\Play\ffmock\demo\tst\Test.cpp(50): error C2988: unrecognizable template declaration/definition
C:\Play\ffmock\demo\tst\Test.cpp(50): error C2059: syntax error: '' C:\Play\ffmock\demo\tst\Test.cpp(92): error C3889: call to object of class type 'Mocks::FFRegCloseKey': no matching call operator found C:\Play\ffmock\demo\tst\Test.cpp(50): note: could be 'int ffmock::Mock<LSTATUS,LSTATUS (HKEY),6,0>::operator ()(Args_t &...)'

The terminal process "C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.38.33130\bin\Hostx86\x86\cl.exe '/nologo', '/Fodemo/bin/x64/', '/std:c++17', '/EHsc', '/D_DEBUG', '/D_X86_', '/DWIN32', '/D_UNICODE', '/DUNICODE', '/D_CONSOLE', '/DFFMOCK_IMPORT=__declspec(dllexport)', '/c', 'C:\Play\ffmock\demo\tst\Test.cpp'" terminated with exit code: 2. * Press any key to close the terminal.

修复建议

1. 扩展function_traits以支持32位API调用约定

32位Windows API默认使用__stdcall调用约定(APIENTRY在32位下等价于__stdcall),而原有function_traits模板只处理了不带调用约定的函数类型,导致模板特化不匹配。需要添加对应特化版本:

namespace ffmock
{
// ... 原有代码 ...

/**
 * @brief 支持__stdcall调用约定的API特化
 */
template<typename RetType_t, typename... Args_t>
struct function_traits<RetType_t(__stdcall)(Args_t...)>
{
    using Ret_t = RetType_t;
    using Sig_t = Ret_t(Args_t...);
    using Ptr_t = Ret_t(__stdcall*)(Args_t...);
    using Api_t = std::function<Sig_t>;
};

// ... 原有代码 ...
}

如果需要兼容更多调用约定(如__cdecl),可以继续添加对应的特化模板。

2. 调整调用运算符的参数类型

原operator()使用Args_t&...左值引用参数,当传入无法绑定左值引用的参数时会出现匹配问题。改为转发引用或值传递提升兼容性:

使用转发引用:

template<typename... Args_t>
Ret_t operator()(Args_t&&... Args)
{
    // 实现逻辑
}

或者直接值传递(适合Win32 API的基础类型参数):

template<typename... Args_t>
Ret_t operator()(Args_t... Args)
{
    // 实现逻辑
}

3. 修正编译输出路径(可选)

32位编译时输出路径写的是/Fodemo/bin/x64/,建议改为对应32位路径(如/Fodemo/bin/x86/),避免文件冲突,但这不是编译错误的直接原因。

修改后重新用32位MSVC编译即可解决报错问题。

内容的提问来源于stack exchange,提问作者Uriel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 09:14:52