【问题标题】:Why do two functions have the same address?为什么两个函数有相同的地址?
【发布时间】:2023-04-05 01:17:02
【问题描述】:

考虑这个函数模板:

template<typename T>
unsigned long f(void *) { return 0;}

现在,我将f&lt;A&gt;f&lt;B&gt; 的地址打印为:

std::cout << (void*)f<A> << std::endl;
std::cout << (void*)f<B> << std::endl;

如果在 MSVS10 中编译,为什么它们会打印相同的地址?它们不是两个不同的功能,因此应该打印不同的地址吗?

更新:

我意识到在 ideone 上,它会打印不同的地址。 MSVS10 优化了代码,因为函数不依赖于T,所以它产生相同的函数。 @Mark 对此的回答和 cmets 很有价值。 :-)

【问题讨论】:

  • @NicolBolas:通过链接。点击问题中的same address
  • 标准是否规定函数必须具有唯一的地址?我认为他们会将其保留为完全未定义(实现定义)以允许编译器优化。
  • 当然,如果你把函数体改成依赖于模板类型,那么函数就不再一样了。
  • @MarkRansom:但根据你的说法,它仍然是相同的功能,因为它打印1。 @bdonlan 的回答似乎是正确的。
  • 我建议即使您遵循 bdorian 的建议,您仍然会得到相同的地址,除非函数的签名或主体在某种程度上取决于模板参数。您的原始函数体不依赖于模板参数,但您的第二个版本依赖。

标签: c++ function templates memory-address function-templates


【解决方案1】:

你需要投到void *:

std::cout << (void*)(ftype*)f<A> << std::endl;
std::cout << (void*)(ftype*)f<B> << std::endl;

如果您强制转换为函数指针(或其他几类非 void 指针),它将被 operator&lt;&lt; 解释为 bool for std::ostream(因此是 1)。

【讨论】:

  • 如果我转换为void*,它会给出编译错误。另外,如果我改为投到 ftype* 也没关系。
  • @Nawaz:您需要先转换为(ftype*),然后再转换为(void*),例如std::cout &lt;&lt; (void*)(ftype*)&amp;f&lt;A&gt; &lt;&lt; std::endl;.
【解决方案2】:

由于函数不依赖于模板参数,编译器可以将所有实例化压缩成一个函数。

我不知道你为什么得到1 的地址。


Nawaz添加:

我用我的真实代码进行了实验,得出的结论是@Mark上面所说的在这里非常重要:

由于函数不依赖于模板参数,编译器可以将所有实例化为一个函数。

我还得出一个结论,如果函数体依赖于T*,而不是T,它仍然会在我的真实代码中为不同类型的参数生成相同的函数(虽然不是在ideone上)。但是,如果它依赖于T,那么它会产生不同的功能,因为sizeof(T) 对于不同类型的参数是不同的(幸运的是我)。

所以我在函数模板中添加了一个T类型的虚拟自动变量,这样函数就可以依赖T的大小,从而强制它产生不同的函数。

【讨论】:

  • 我用我的真实代码进行了实验,得出的结论是这些信息很重要:由于函数不依赖于模板参数,编译器可以将所有实例化为一个函数。 我还得出一个结论,如果函数体依赖于T*,而不是T,它仍然会产生相同的函数。但是,如果它依赖于 T,那么它会产生不同的功能,因为 sizeof(T) 对于不同的类型参数(幸运的是)不同。
【解决方案3】:

这只是未定义行为的一种情况,因为将指向函数的指针转换为指向对象类型的指针的结果是未定义的。

要检查的更有趣的表达式是f&lt;A&gt; == f&lt;B&gt;,当且仅当AB 引用相同的类型时,它的计算结果应为true

【讨论】:

  • 这是有问题的。证据在哪里?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-18
  • 1970-01-01
  • 2021-05-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多