未使用函数参数的编译器优化

Posted

技术标签:

【中文标题】未使用函数参数的编译器优化【英文标题】:Compiler optimization on not used function parameters 【发布时间】:2019-03-17 13:17:29 【问题描述】:

这几天我在使用 Windows RPC 时遇到了一个奇怪的问题。现在我找到了解决方案,但我想知道防止这个问题的正确方法是什么。

所以基本上我在调用NdrClientCall2 函数时遇到了问题。正如您在文档中看到的,此函数的第三个参数是指向客户端调用堆栈的指针。我将 midl.exe 生成的 C 代码更改为我自己的 C++ 版本,所以我的调用者看起来像这样:

void CppRpc::InternalCommand(int pSize, char buffer[1000000]) const

    RpcTryExcept
    
        NdrClientCall2(PMIDL_STUB_DESC(&m_rpc_stup_description),
            PFORMAT_STRING(&MIDL_PROCFORMAT_STRING.Format[0]),
            reinterpret_cast<unsigned char *>(&pSize));
    
    RpcExcept(1)
    
        std::cerr << "Runtime reported exception " << RpcExceptionCode()
            << std::endl;
    
    RpcEndExcept

在使用完全优化的发布模式下,我遇到访问冲突一两天,然后我明白由于此函数中未使用参数buffer,编译器优化会以某种方式删除此参数。

但是我需要将此参数放在堆栈上,以便NdrClientCall2 可以将其流式传输到服务器。如果我将buffer 的任何用途(例如char dummy = buffer[0];)添加到功能伙伴中,那么它将正常工作。

所以我的问题是,如何防止这种情况下的优化? 我正在使用 Visual Studio 2017。

【问题讨论】:

【参考方案1】:

我不建议这样做。因为InternalCommand 是您的内部函数,所以编译器可能会更改其参数的布局。而(据我了解)您需要特定的布局,其中有一个 int 变量,后跟为堆栈保留的缓冲区。

如果您更改函数调用约定(即cdeclstdcall),这种布局也可能会改变。

我将定义一个带有单个 int 字段的结构 (POD),将指向它的指针传递给您的函数,而调用者分配的实际结构具有更大的大小。

类似这样的:

struct StackFrame

    int pSize;
    char pStack[1000000]; // stack goes here
;

// ...

void CppRpc::InternalCommand(StackFrame* pStack) const

    RpcTryExcept
    
        NdrClientCall2(PMIDL_STUB_DESC(&m_rpc_stup_description),
            PFORMAT_STRING(&MIDL_PROCFORMAT_STRING.Format[0]),
            reinterpret_cast<unsigned char *>(pStack));
    
    RpcExcept(1)
    
        std::cerr << "Runtime reported exception " << RpcExceptionCode()
            << std::endl;
    
    RpcEndExcept

【讨论】:

尤其如此,因为并非所有处理器都首先在堆栈上传递参数,即使是基于堆栈的,也可能不会从右到左传递。取pSize的地址,不代表buffer紧随其后。 我知道已经有一段时间了,但我只是想告诉您,尽管您的方法是最合理的方法,但对我不起作用(我真的不知道为什么,它会抛出异常装配级别,它应该是 Windows RPC 的东西)。无论如何,我再次检查了 MIDL 自动生成的 C 代码,我注意到它在客户端使用 #pragma optimize("", off) 来禁用该文件的编译器优化(这一定是无法解决的问题,导致他们这样做)。我这样做了,然后它按预期工作正常。对于任何陷入这种确切情况的人,我都会留下此评论。

以上是关于未使用函数参数的编译器优化的主要内容,如果未能解决你的问题,请参考以下文章

编译器会优化未使用的链接文件吗?

模板参数作为函数说明符和编译器优化

(Linux)gcc进行优化编译的参数是啥?

C++:编译器能否优化按值传递?

C ++编译器能否优化使用用于将函数结果传递给另一个函数的虚拟变量?

编译器在添加字符时停止优化未使用的字符串