c - 冗余赋值消除是否相当典型的优化



给定以下内容:

len = strlen(str);
/* code that does not read from len */
len = new_len;

我可以依靠编译器来删除第一行吗?

我正在编写一个代码生成脚本。第一行在一个地方生成,而后面的所有内容在其他地方生成(由后代类中的虚函数生成)。大多数时候,不需要 len。但有时确实如此。我想知道我是否可以在所有情况下都设置它,并在不需要时让编译器摆脱该行。

不,当然,您不能"依赖"编译器所做的优化选择。

它们可以根据用户的心血来潮(编译器命令行选项)或使用不同的编译器版本进行更改。

由于您描述的行为不是语言标准所要求的,因此您不能依赖编译器来实现它。

另一方面,您当然可以测试它,并尝试"诱导"它被优化出来,例如(再次)要求编译器进行尽可能多的优化。

编译器非常聪明。但是依靠编译器删除"未使用"的函数调用可能不是一个好主意。首先,编译器需要理解你正在调用的函数(所以strlen在这里是一个很好的例子,因为大多数编译器都了解strlen做什么以及它如何影响其他事情) - 如果函数不是编译器"理解"的函数,那么它就无法优化它。

如果你这样做了怎么办:

 x = printf("Hello, World!n");
 x = printf("World, Hello!n");

你认为他们的编译器通过删除第一个 printf 做了正确的事情吗?应该不会...因此,对于编译器无法确定"没有副作用"的任何函数,编译器必须调用该函数,即使未使用结果也是如此。无副作用意味着在正常情况下 - 例如,使用无效指针调用 strlen() 有副作用 - 您的代码可能会崩溃 - 但这不是"正常情况" - 使用 strlen() 只是为了检查您的指针是否有效,对吧?

因此,换句话说

,您可能希望在调用 strlen 之前确保确实需要对 strlen() 的调用 - 或者接受编译器可能会生成不必要的 strlen 调用的事实。

现代编译器似乎在消除冗余赋值方面做得非常出色。我通过 VS 2008 和 gcc 4.6 运行了以下代码片段,实际上删除了对 strlen(更确切地说是内联代码)的调用。两个编译器都设法看到something()something_else()都没有产生副作用。对这些的调用也会被删除。

这发生在 VC 中的/O1 和 gcc 中的/O1 处。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int something(int len)  {
    if(len != len) {
        printf("%dn", len);
    }
    return 0;
}
int something_else(int len) {
    return len * len;
}
int main(void) {
    char *s = malloc(1000);
    size_t len;
    strcpy(s, "Hello world");
    len = strlen(s);
    something(len);
    printf("%sn", s);
    len += 8;
    something_else(len);
    len = 5;
    printf("%dn", len);
    return 0;
}

这取决于编译器和您指定的优化级别。

在这里,它最初是从函数调用中分配的。如果该功能有副作用怎么办?
因此,您不能只是假设编译器为您优化它。

如果初始赋值语句没有任何副作用,并且您指定了足够好的优化级别(例如,在 gcc 的情况下为 -O3),它可能会为您优化它。

最新更新