0

鉴于以下情况:

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

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

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

4

4 回答 4

4

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

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

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

另一方面,您当然可以对其进行测试,并尝试通过(再次)要求您的编译器进行尽可能多的优化来“哄骗”它进行优化。

于 2013-01-23T14:10:25.653 回答
2

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

如果你这样做了:

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

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

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

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

于 2013-01-23T14:24:14.713 回答
1

现代编译器似乎在消除冗余分配方面做得非常出色。我通过 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("%d\n", 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("%s\n", s);
    len += 8;
    something_else(len);
    len = 5;
    printf("%d\n", len);
    return 0;
}
于 2013-01-23T17:54:49.523 回答
0

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

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

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

于 2013-01-23T14:11:04.007 回答