【发布时间】:2018-04-08 03:58:30
【问题描述】:
我可以将see it listed 作为现代 C++ 习语之一,但它到底是什么?
它只是copy elision的一种吗?
【问题讨论】:
-
Evaluating strlen at compilation time? 的可能重复项之一是您的问题的答案。
-
@S.M.不,这不是我问题的答案。正确答案见下文。
我可以将see it listed 作为现代 C++ 习语之一,但它到底是什么?
它只是copy elision的一种吗?
【问题讨论】:
您可能知道std::strlen 循环遍历整个字符串。在某些情况下,这可能效率低下,因为这意味着 CPU 必须开始计算字符数,这会降低其他内容的缓存局部性。
但在大多数情况下,编译器能够优化std::strlen 并计算字符串本身的字符数,而不是让生成的程序执行此操作。这有时称为 strlen 省略(因为它省略了对 strlen 的调用)。
std::strlen 中的simple example 将完全得到优化。
#include <cstring>
int main() {
return std::strlen("hi");
}
在-O3 下生成的程序集是
main: # @main
mov eax, 2
ret
即使under -O0 也不会生成循环!
现在这是一个相当简单的示例,但它甚至适用于更复杂的 std::strlen 用法。
#include <cstring>
int main(int argc, char**) {
const char *string;
if (argc == 1)
string = "hello";
else if (argc == 2)
string = "world";
else if (argc == 3)
string = "!";
return std::strlen(string);
}
这里的字符串完全是optimized away,以及std::strlen 调用。
【讨论】:
恕我直言,如果编译器理解 strlen 的语义,并且如果有问题的字符串在编译时已知,那么编译器可以只发出一个常量而不是评估运行时字符串的长度(通过任何方式)。这就是这里发生的一切。相信微软的营销部门会大肆宣传这样一个简单的功能。
我对这一切感兴趣的是(优化)编译器将常用的运行时库函数视为内在函数并在可能的情况下为它们发出更好的代码的增长趋势。这已经持续了一段时间 - memcpy 和 memset 是明显的例子 - 但我最近在 Godbolt 的 Compiler Explorer 中玩耍,很惊讶地看到 gcc 替换了它:
printf (" ");
用这个:
putchar (' ');
震惊?我也是,我不确定我是否喜欢它。我可能有一个定制的 printf 可以做一些特别的事情,而这种诡计会让人大吃一惊。在我看来,如此小的收益(编译器编写者)是一个很大的风险。
【讨论】:
printf,那么你不是在编写标准的 C 或 C++,而是你自己。
myprintf,但你不应该尝试写自己的printf。