鉴于以下情况:
len = strlen(str);
/* code that does not read from len */
len = new_len;
我可以依靠编译器删除第一行吗?
我正在编写代码生成脚本。第一行在一个地方生成,而后面的所有内容都在其他地方生成(通过后代类中的虚函数)。大多数时候,不需要 len。但有时,确实如此。我想知道我是否可以在所有情况下都设置它,如果不需要,让编译器摆脱这条线。
鉴于以下情况:
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("%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;
}
这取决于您指定的编译器和优化级别。
在这里,它最初是从函数调用中分配的。如果该功能有副作用怎么办?
所以你不能只假设编译器会为你优化它。
如果初始赋值语句没有任何副作用并且您指定的优化级别足够好(例如,在 gcc 的情况下为 -O3),它可能会为您优化它。