可以在编译期间对函数进行评估吗?

时间:2016-01-07 04:36:56

标签: compilation language-agnostic compiler-optimization

考虑以下功能,

public static int foo(int x){
     return x + 5;
}

现在,我们来称呼它,

int in = /*Input taken from the user*/;
int x = foo(10);     // ... (1)
int y = foo(in);     // ... (2)

此处,编译器可以更改

int x = foo(10);     // ... (1)

int x = 15;     // ... (1)

通过在编译期间评估函数调用,因为在编译期间函数的输入可用吗?

我理解在标记为(2)的呼叫期间无法进行此操作,因为输入仅在运行时可用。

我不想知道以任何特定语言进行此操作的方法。我想知道为什么这可能是也可能不是编译器本身的特性。

2 个答案:

答案 0 :(得分:2)

C ++确实有一个方法:

在C ++ 11中阅读'constexpr'关键字,它允许对函数进行编译时评估。

它们有一个限制:函数必须是return语句(不是多行代码),但可以调用其他constexpr函数(C ++ 14没有此限制AFAIK)。

static constexpr int foo(int x){
     return x + 5;
}

编辑: 为什么编译器可能不会评估函数(只是我的猜测):

通过在不被告知的情况下评估函数来删除函数可能不合适。

该函数可用于不同的编译单元,也可用于静态/动态输入:因此在某些情况下评估它并在其他地方添加调用。

这种使用会提供不一致的执行时间(特别是在像AVR这样的确定性平台上),其中时间可能很重要,或者至少需要是可预测的。

此处也可以发挥中断(以及编译器如何与它们交互)。

编辑:

  

constexpr实际上更强大 - 它要求编译器执行此操作。编译器可以在没有constexpr的情况下自由折叠函数,但程序员不能依赖它。

  

你可以举例说明用户会从中受益,但编译器选择不这样做吗?

inline函数可能会或可能不会解析为可以优化为最终结果的常量表达式。

然而,constexpr保证了它。内联函数不能用作编译时常量,而constexpr可以允许你编写编译时函数,更多的是对象。

constexpr保证内联不能保证的基本示例。

constexpr int foo( int a, int b, int c ){
  return a+b+c;
}

int array[ foo(1, 2, 3) ];

与简单对象相同。

struct Foo{
  constexpr Foo( int a, int b, int c ) : val(a+b+c){}
  int val;
};

constexpr Foo foo( 1,2,4 );

int array[ foo.val ];

除非foo.val是编译时常量,否则上面的代码将无法编译。

即使只是一个函数,内联函数也无法保证。在编译语法之后,链接器也可以对多个编译单元进行内联(检查数组边界是否为整数常量)。

这有点像元编程,但没有模板。当然,这些示例并不是主题正义,但是非常复杂的解决方案将受益于使用对象和函数式编程来实现结果的能力。

答案 1 :(得分:0)

是的,评估可以在编译期间进行。这属于常量折叠和函数内联的标题,这两者都是优化编译器的常见优化。

许多语言在"编译时间"之间没有很强的区别。和#34;运行时间",但一般规则是该语言定义了一个"执行模型"它定义了具有任何特定输入的任何特定程序的行为(或指定它是未定义的)。编译器必须生成一个可执行文件,该文件可以读取任何输入并生成执行模型定义的相应输出。只要外部查看的行为是正确的,可执行文件中 内部发生的事情并不重要。

此处"输入","输出"和"行为"包括执行模型中定义的与环境的所有可能交互,包括时序效应。