例如:
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
}
有谁知道这背后的原因?起初我以为这是因为函数不存在于内存中,因为我从不调用它们,因此它们永远不会被添加到堆栈中。但即使是指向main函数的指针的值也会输出1。
答案 0 :(得分:7)
函数指针不会隐式转换为void *
,这是operator <<
重载的原因。
这由C ++11§4.10/ 2中的省略指定:
类型为“指向cv T的指针”的prvalue,其中T是对象类型,可以转换为类型为“指向cv void的指针”的prvalue。将“指向cv T的指针”转换为“指向cv void的指针”的结果指向T类型的对象所在的存储位置的开始,就好像该对象是类型T的最派生对象(1.8) (即,不是基类子对象)。空指针值将转换为目标类型的空指针值。
函数类型不是对象类型。
此外,您甚至无法使用static_cast
进行此操作。函数和对象可以存在于完全不同的地址空间(这称为哈佛架构),具有不同大小的指针。将函数指针转换为void *
可以 完成reinterpret_cast
:它是“有条件支持的”(C ++11§5.2.10/ 8)。这样的void *
只能用于打印或转换回原始函数指针类型。
答案 1 :(得分:2)
像这样使用它,或者它将被转换为bool
类型。
cout << reinterpret_cast<void*>(ptrOne) << endl;
答案 2 :(得分:1)
C ++中的运算符重载增加了各种令人讨厌的复杂性。 (它可以让你做出很棒的东西 - 但有时它只是令人头痛。)
正如其他答案中所解释的,C ++正在对函数指针进行一些自动类型强制。如果你只是使用好的'C风格printf
,你应该得到你期望的结果:
#include <cstdio>
// ...
printf("func1: %p\nfunc2: %p\n", funcOne, funcTwo);
答案 3 :(得分: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;