我如何创建一个最小的测试用例来说明/ EHs的成本?

Lig*_*ica 5 c++ exception visual-studio visual-studio-2019

当我将Visual Studio 2019从/EHsc(仅限结构化和C ++例外)切换到/EHs(也不要假设extern "C"函数不会抛出– ref)时,我试图调查生成的代码的差异,但是我似乎无法哄骗VS当我最小化它时提供一个有用的测试用例。

我很惊讶以下内容没有做到这一点(两种情况下的程序集都是相同的),因为fptr优化器不知道所引用的函数的内容(可能的定义包含在说明中)。

void foo();

/*void foo()
{
    throw 0;
}*/

extern "C"
void bar(void (*fptr)())
{
    fptr();
}

int main()
{
    try
    {
        bar(&foo);
    }
    catch (...) {}
}
Run Code Online (Sandbox Code Playgroud)

当然,它知道任何假定的异常都会被立即捕获,并且由于/EHsc该异常的传播结果对于Microsoft而言是“未定义的”,因此它的“出现”当然是有效的结果。但这对我没有太大帮助!

那么,如何在不引入不同翻译单元的情况下执行此实验?理想情况下,我希望能够为此提供一个Compiler Explorer片段。

我的目标是证明extern "C"以良好定义的方式允许抛出(或传播)C ++异常不会比我在交易中接受的运行时成本高。

是的,我知道一般性建议,不要让异常跨越模块边界或流经第三方C代码。是的,我还是这样做。是的,这在我们的项目中很好!

Adr*_*ica 0

下面的MCVE可能会给你一些关于测试框架的想法。您可以轻松添加更多“彻底”的测试代码,但这将编译并运行。请注意,/EHsc设置该选项后,会生成此警告:

警告 C5039:“FuncTst”:指向传递给 -EHc 下的 extern C 函数的潜在抛出函数的指针或引用。如果此函数引发异常,则可能会发生未定义的行为。

然而,当使用时/EHs警告消失 - 这表明至少有可能生成不同的代码。

这是建议的代码:

#pragma warning(disable:4514) // These two lines de-fluff the hundreds of other
#pragma warning(disable:4710) // warning generated when /Wall is used.

#include <iostream>

using pFunc = int(__stdcall*)(int);

extern int __stdcall FuncOne(int p) {
    int answer = 0;
    for (int i = 0; i < p; ++i) answer += i / p; // Possible divide-by-zero
    return answer;
}

extern "C" int __stdcall FuncTst(int i, pFunc fnc) noexcept // Expects noexcept but "FuncOne" can throw!
{
    return fnc(i);
}

int main()
{
    int q;
    std::cout << "Enter test number: ";
    std::cin >> q;
    int z = FuncTst(q, FuncOne);
    std::cout << "Result = " << z << std::endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

希望能帮助到你!请随意提出批评和/或要求任何“改进”或解释。

注意:虽然在使用(例如)进行编译时无法专门启用警告,但您可以强制将其标记为错误(尽管这可能有点苛刻),方法是:C5039\W4

#pragma warning(error:5039)
Run Code Online (Sandbox Code Playgroud)