c++ - 编译时计算 (C++ v. C)
问题描述
我知道该constexpr
关键字可用于在 C++ 中执行编译时计算。例如:
constexpr int factorial(int n)
{
return n <= 1 ? 1 : (n * factorial(n - 1));
}
(取自https://en.cppreference.com/w/cpp/language/constexpr)
编译时计算可以被认为是 C++ v. C 的一个关键优势吗?
据我了解,编译时计算在 Cconstexpr
中是不可能的。不可用,我相信代码必须在运行时进行评估。
与等效的 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");
}
由于后者而不是前者,它必须无法编译。 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));
}
使用 GCC 10.2 编译为带有 -O3的C 程序,并且由于as-if规则,程序变成
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
哪个更直接对应
unsigned factorial(unsigned n) {
unsigned i = 1;
while (n > 1) {
i *= n;
n --;
}
return i;
}
int main(void) {
printf("%d\n", 3628800);
}
即编译器不仅将递归展平为一个简单的while
循环,而且还解析了常量的阶乘,而且都没有任何特殊的关键字。
推荐阅读
- c++ - 是什么阻止了 Boost.Format 表单使用我的流运算符重载作为可选 int?
- outlook - 如何在新的 Outlook 邮件中创建永久通知?
- python - Python:将二进制数组显示为图像
- c# - 如何通过双击.NET框架中的exe等文件来运行.NET核心应用程序
- python - Python数据框按以下值分组
- azure - 缓存管理 Power BI Services 和 Azure Analysis Services 多维数据集
- mysql - 从 Mysql 5.5 升级后 Percona 5.7 缓慢的“发送数据”
- python - 在 Python 中定义列表列表的第一个元素
- php - 使用 SQL 查询更改 Woocommerce 产品类别名称
- testing - Flutter:如何模拟流