tha*_*ude 7 c c++ metaprogramming compile-time constexpr
我知道该constexpr关键字可用于在 C++ 中执行编译时计算。例如:
constexpr int factorial(int n)
{
return n <= 1 ? 1 : (n * factorial(n - 1));
}
Run Code Online (Sandbox Code Playgroud)
(取自https://en.cppreference.com/w/cpp/language/constexpr)
能否将编译时计算视为 C++ 与 C 的主要优势?
据我了解,在 C 中不可能进行编译时计算。constexpr不可用,我认为必须在运行时评估代码。
这是 C++ 程序与等效 C 程序相比可以获得更好性能(例如速度)的一种方式吗?
只有一件事是确定的 - 编译时计算使 C++ 编译器必然更复杂,编译速度必然会更慢,因为编译器需要在编译时进行;见例如
constexpr int factorial(int n) {
return n <= 1 ? 1 : (n * factorial(n - 1));
}
int main(void) {
static_assert(factorial(10) == 3628800, "factorial 10 was correct");
static_assert(factorial(3) == 42, "factorial 3 was 42");
}
Run Code Online (Sandbox Code Playgroud)
由于后者而不是前者,因此必须无法编译。 static_assert
AC 编译器不需要这样的复杂性,因为没有要求 C 编译器必须能够在编译期间计算递归函数的值。一个简单的 C 编译器可以很好地将每条语句分别组装成机器代码,而无需记住前面的语句做了什么。C 标准当然不要求它能够在编译时评估递归函数。
但这并不是说在编译期间没有 C 编译器会这样做。看这个例子:
#include <stdio.h>
int factorial(int n) {
return n <= 1 ? 1 : (n * factorial(n - 1));
}
int main(void) {
printf("%d\n", factorial(10));
}
Run Code Online (Sandbox Code Playgroud)
与GCC 10.2作为编译C程序与-O3,并感谢了AS-如果规则,程序成为
factorial:
mov eax, 1
cmp edi, 1
jle .L4
.L3:
mov edx, edi
sub edi, 1
imul eax, edx
cmp edi, 1
jne .L3
ret
.L4:
ret
.LC0:
.string "%d\n"
main:
sub rsp, 8
mov esi, 3628800
mov edi, OFFSET FLAT:.LC0
xor eax, eax
call printf
xor eax, eax
add rsp, 8
ret
Run Code Online (Sandbox Code Playgroud)
哪个更直接对应
unsigned factorial(unsigned n) {
unsigned i = 1;
while (n > 1) {
i *= n;
n --;
}
return i;
}
int main(void) {
printf("%d\n", 3628800);
}
Run Code Online (Sandbox Code Playgroud)
即编译器不仅将递归扁平化为一个简单的while循环,而且还解析了常量的阶乘,并且所有这些都没有任何特殊的关键字。