我可以告诉我的编译器忽略语句或函数的副作用吗?

ein*_*ica 4 c++ side-effects compiler-optimization compiler-options elision

假设我的代码具有以下功能:

inline int foo() {
    bar();
    int y = baz();
    return y;
}
Run Code Online (Sandbox Code Playgroud)

并假设bar()baz()有副作用。

如果我写:

int z = foo();
printf("z is %d\n", z);
Run Code Online (Sandbox Code Playgroud)

那么显然都bar()baz()必须执行。但如果我写:

foo();
Run Code Online (Sandbox Code Playgroud)

并且不使用返回值,调用的唯一原因baz()是它的副作用。

有没有一种方法可以告诉我的编译器(对于:GCC、clang、MSVC、Intel 中的任何一个),例如“baz()为了决定是否优化它,您可能会忽略它的副作用”?或者“为了决定是否优化它,您可能会忽略此指令的副作用”?

这个问题是针对 C 和 C++ 提出的,但可能与各种过程语言相关。让我们使用 C++,因为这是我现在最常用的。

笔记:

  • bar()baz()不在我的控制之下。
  • 的签名foo()不得更改。当然baz(),如果我愿意,我可以使用一些代理并懒惰地应用;或者只是为不使用的情况编写一个不同的函数y。这不是我要问的。

Nat*_*dge 5

作为标准 C 和 C++ 的扩展,gcc 和 clang 支持pure function 属性,该属性通知编译器该函数没有副作用并且可以删除不需要的调用。如果你用这个属性声明一个函数,编译器会相信你,即使你在撒谎。

#include <iostream>

static int foo() __attribute__((pure));

static int foo() {
  std::cout << "I am a side effect!" << std::endl;
  return 17;
}

int main() {
  foo();
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

这不打印输出。 请注意,这clang会警告您忽略pure函数的返回值。

(特别是,当您在 C 中执行类似操作时,gcc 会优化调用 with-O0,但将其保留为-O2!)

函数的定义不需要在范围内才能工作,即使先前的声明已经在范围内,您也可以重新声明具有此属性的函数。所以它也可以用于库函数。 例子。

当然,对编译器撒谎总是由您自己承担风险,并且可以想象这可能会产生我没有想到的潜在不良影响。如果您愿意仔细检查生成的代码以确保它真的按照您的意愿行事,这可能是一个有用的技巧,但我不会太相信它。