为什么函数地址不是常量表达式?

12

有没有一种方法可以在常量表达式中使用函数地址?

void foo()
{}

int main()
{
  static_assert(&foo, "test error");
}

这段代码无法编译。

错误:C2057: 预期常量表达式。

代码的目的是在编译时比较两个函数地址。

2个回答

6

这绝对是编译器的一个bug。

函数可以作为模板参数,这意味着它们是const表达式。(参见ideone)。

此外,上面的代码在gcc 4.6.1下可以编译通过,尽管ideone无法编译它,但是ideone使用的是gcc-4.5.1,该版本存在与您的代码相关的错误。


4
这可能有点棘手。函数地址的一个问题是编译器不一定知道它的值(它可能在不同的翻译单元中被定义,或者根本没有定义)。对于这些情况,&foo编译时的预期结果是什么?(我并不是说它不能被完成,但这个表达式被认为是odr-use,所以编译器可以假设它必须被定义,并让链接器解析地址,如果没有定义,则会失败。但是,我建议去标准文件中寻找权威答案来回答这个问题。 - David Rodríguez - dribeas
3
函数在编译时已知,但它们的地址未知。符号名称在编译时用于链接器后续进行内存映射。更加复杂的是,在C++引入模板之后,链接器几乎普遍地开始折叠具有相同已编译代码的函数。因此,两个不同的函数在运行时可能具有相同的地址。编译器不会预先知道这一点。 - Drew Dormann
1
由于函数可以在加载时重新定位(类似于Windows DLL),因此我无法看到如何在一般情况下知道&foo,直到程序运行。 - David Heffernan

3
这是我的理解,供参考:
函数类型在编译时已知,但函数地址只有在链接时才能确定。因此,您可以将函数类型用作模板参数,但地址不是编译时常量/已知的。
在您的示例代码中,编译器可以推断出地址在编译时为非零,但它无法知道具体的地址。这不是编译器的错误。

地址在链接时甚至都不知道。代码经常在加载时被重新定位。 - David Heffernan
1
真的,但是在同一可加载模块内的相对地址在链接时是已知的,因此函数跳转可以被“连接起来”。我的观点只是函数地址可以在运行时逻辑上获取(即:语言保证这是合法的),但不能在编译时获取。 - Nick

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接