如何确保某些代码被优化掉?

Bor*_*rph 6 c++ unit-testing dead-code compiler-optimization c++11

tl;dr:能否以某种方式确保(例如通过编写单元测试)某些东西被优化掉,例如整个循环?

确保生产版本中不包含某些内容的常用方法是将其包装为#if...#endif. 但我更喜欢继续使用 C++ 机制。即使在那里,我也喜欢保持简单的实现,而不是复杂的模板专业化,并认为“嘿,编译器无论如何都会优化它”。

上下文是汽车中的嵌入式软件(二进制大小很重要),编译器通常很差。它们在安全意义上得到了认证,但通常在优化方面表现不佳。

示例 1:在容器中,元素的销毁通常是一个循环:

for(size_t i = 0; i<elements; i++)
    buffer[i].~T();
Run Code Online (Sandbox Code Playgroud)

这也适用于内置类型,例如int,因为标准允许显式调用任何标量类型的析构函数 (C++11 12.4-15)。在这种情况下,循环不执行任何操作并被优化掉。在 GCC 中是这样,但在另一个(Aurix)中不是,我在反汇编中看到了一个字面上的空循环!因此需要模板专门化来修复它。

示例 2:代码,仅用于调试、分析或故障注入等:

constexpr bool isDebugging = false; // somehow a global flag
void foo(int arg) {
    if( isDebugging ) {
        // Albeit 'dead' section, it may not appear in production binary!
        // (size, security, safety...)
        // 'if constexpr..' not an option (C++11)
        std::cout << "Arg was " << arg << std::endl;
    }
    // normal code here...
}
Run Code Online (Sandbox Code Playgroud)

当然,我可以看一下拆解。但作为一种上游平台软件,很难控制可能使用的所有目标、编译器及其选项。人们非常担心,由于任何原因,下游项目会出现代码膨胀或性能问题。

底线:是否有可能以某种方式编写软件,即已知某些代码可以像 a 那样以安全的方式进行优化#if?或者单元测试,如果优化未达到预期,则会失败?

[针对第一个问题,我想到了计时测试,但作为裸机,我还没有方便的工具。]

Xir*_*ema 5

if constexpr是用于此类测试的规范 C++ 表达式 (C++17 起)。

constexpr bool DEBUG = /*...*/;

int main() {
    if constexpr(DEBUG) {
        std::cerr << "We are in debugging mode!" << std::endl;
    }
}
Run Code Online (Sandbox Code Playgroud)

如果DEBUG为 false,则根本不会生成打印到控制台的代码。因此,如果您有检查代码行为所需的日志语句之类的内容,但您不想在生产代码中与之交互,则可以将它们隐藏在if constexpr表达式内,以便在代码移至生产。

  • @t.niese 如果编译器的行为不可靠,那么就没有可能的答案可以满足OP的要求。我的理解是“编译器有缺陷”是口语提喻,意思是“我担心我们正在做的事情是非标准行为,因此不能依赖于其他环境”。如果OP使用的编译器确实有缺陷或不可靠,那么我们可以给他们的唯一可能的建议是“停止使用有缺陷的编译器”。 (2认同)

Bri*_*ian 4

可能有一种更优雅的方法,它不是单元测试,但如果您只是寻找特定的字符串,并且可以使其唯一,

strings $COMPILED_BINARY | grep "Arg was"
Run Code Online (Sandbox Code Playgroud)

应该显示该字符串是否被包含在内