3

我对编译器的专业知识很少(没有读过),并且想知道以下代码片段是否会由相对较新的(VS2008+/GCC 4.3+)编译器自动优化:

Object objectPtr = getPtrSomehow();

if (objectPtr->getValue() == something1)       // call 1
    dosomething1;
else if (objectPtr->getValue() == something2)  // call N (there are a few more)
    dosomething2;

return;

其中 getValue() 仅返回一个成员变量,该成员变量是枚举之一。(该调用没有可观察到的效果)

我的编码风格是在“开关”之前进行一次调用并保存值以将其与每个 somethingX 进行比较,但我想知道这对于今天的编译器是否有争议。

我也不确定自己用谷歌搜索什么来找到答案。

谢谢,

AK

4

4 回答 4

4

这没有实际意义,特别是如果方法是可变的。

如果getValue未声明const,则无法优化调用,因为后续调用可能返回不同的值。

如果它被声明,编译器优化调用const更容易,但也不是微不足道的。它需要访问实现,以确保调用没有副作用。即使被标记const(修改并返回全局),它也有可能返回不同的值。

于 2012-12-06T19:37:21.363 回答
3

getValue()除非编译器可以在编译那段代码时检查其定义,否则它不能忽略第二次调用,因为它不知道该调用是否具有可观察的效果以及第二次是否返回相同的值。

即使它看到了定义,它也可能(这是我对一些编译器内部结构的疯狂猜测)不会特意去检查它。您唯一的机会是实现是微不足道的内联两次,然后被公共子表达式消除所捕获。编辑:由于定义在标题中,而且很小,因此(内联和后续的 CSE)很可能会发生。不过,如果您想确定,请检查g++ -O2 -S您的编译器的输出或等效项。

所以总而言之,你不应该期望优化会发生。再说一次,getValue可能很便宜,因此不太值得手动优化。与几个机器周期相比,额外的生产线是什么?不多,在大多数情况下。如果您正在编写大量代码,那么您不应该询问而只是检查它(反汇编/分析)。

于 2012-12-06T19:43:18.473 回答
2

正如其他答案所指出的那样,编译器通常无法消除第二次调用,因为可能会有副作用。

然而,一些编译器有办法告诉编译器该函数没有副作用并且允许这种优化。在 GCC 中,函数可以声明为pure。例如:

int square(int) __attribute__((pure));

表示该函数“除了返回一个值之外没有任何作用,并且 [the] 返回值仅取决于参数和/或全局变量。”</p>

于 2012-12-06T19:53:55.520 回答
1

你写了:

我的编码风格是在“开关”之前进行一次调用并保存值以将其与每个 somethingX 进行比较,但我想知道这对于今天的编译器是否有争议。

是的,这是一个有争议的问题。编译器所做的是它的业务。您将忙于编写可维护的代码,而不是试图对一个比我们任何人都希望的工作做得更好的软件进行微观管理。

专注于编写可维护的代码并信任编译器来执行其任务。如果您后来发现您的代码太慢,那么您可以担心优化。

记住一句谚语:

过早的优化是万恶之源。

于 2012-12-06T19:43:41.237 回答