2

例如:

using namespace std;
#include <iostream>

void funcOne() {
}

void funcTwo( int x ) {
}

int main() {

  void (*ptrOne)() = funcOne;
  cout << ptrOne << endl;      //prints 1

  void (*ptrTwo)( int x ) = funcTwo;
  cout << ptrTwo << endl;      //prints 1

  int (*ptrMain)() = main;
  cout << ptrMain << endl;     //prints 1

}

有谁知道这背后的原因?起初我认为这是因为这些函数不存在于内存中,因为我从不调用它们,因此它们永远不会被添加到堆栈中。但即使是指向主函数的指针的值也会打印出 1。

4

4 回答 4

7

函数指针不会隐式转换为void *,这是operator <<重载的原因。

这是由 C++11 §4.10/2 中的省略指定的:

“指向 cv T 的指针”类型的纯右值,其中 T 是对象类型,可以转换为“指向 cv void 的指针”类型的纯右值。将“指向 cv T 的指针”转换为“指向 cv void 的指针”的结果指向类型 T 的对象所在的存储位置的开始,就好像该对象是类型 T 的最派生对象 (1.8) (即,不是基类子对象)。空指针值转换为目标类型的空指针值。

函数类型不是对象类型。

此外,您甚至无法使用static_cast. 函数和对象可能存在于完全不同的地址空间(这称为哈佛架构)中,具有不同大小的指针。void *可以通过以下方式将函数指针转换为:它是“有条件支持的”(C++11 §5.2.10/8)reinterpret_cast这样的 avoid *应该只用于打印或转换回原始函数指针类型。

于 2013-06-30T03:17:14.163 回答
2

像这样使用它,否则它会被转换为一个bool类型。

cout << reinterpret_cast<void*>(ptrOne) << endl;
于 2013-06-30T03:06:08.837 回答
1

C++ 中的运算符重载增加了各种令人讨厌的复杂性。(它也可以让你做一些很棒的事情——但有时它只是让人头疼。)

正如其他答案中所解释的,C++ 正在对您的函数指针进行一些自动类型强制。如果你只是使用好的 ol' C 风格printf,你应该得到你期望的结果:

#include <cstdio>

// ...

printf("func1: %p\nfunc2: %p\n", funcOne, funcTwo);
于 2013-06-30T03:09:12.660 回答
0

试试这个:

void (*ptrOne)() = funcOne;
cout << reinterpret_cast<void*>(ptrOne) << endl;

void (*ptrTwo)( int x ) = funcTwo;
cout << reinterpret_cast<void*>(ptrTwo) << endl;

int (*ptrMain)() = main;
cout << reinterpret_cast<void*>(ptrMain) << endl;

我认为通常,函数重载规则意味着<<被调用的版本是operator<<(bool),这意味着:

cout << ptrOne << endl;

转化为:

cout << (ptrOne != NULL) << endl;

这与以下内容相同:

cout << true << endl;
于 2013-06-30T03:06:22.233 回答