为什么我们可以取消引用函数指针?

6

显然,我是一个指针的新手。我来自没有指针的Java。

我仍然不明白为什么我们可以解引用函数指针?我们可以解引用int指针,因为我们知道int是4个字节,但是我们不能解引用void指针,因为我们不知道它的长度。对于一个函数指针,虽然我们知道函数的返回值和参数的数据类型(长度),但我们不知道函数在文本中的长度,那么我们怎么知道函数的长度以便我们可以解引用它呢?


1
也许这个问题会有所帮助。解释了当您尝试以正常方式(即使用*)取消引用函数指针时会发生什么。 - Bhargav
我看到你对函数指针的长度有些困惑。请参考下面的线程以获得更好的澄清: https://dev59.com/D2865IYBdhLWcg3wLrlE - Gurubaran
"deference" != "dereference" - William Pursell
1
请注意,在C++中,int不一定是四个字节。在正常情况下,它至少是16位,即两个字节,尽管16位的整数和正常情况现在并不太搭配。 - chris
不,这个问题不是关于函数指针的长度,而是关于它所指向的函数的长度。 - MSalters
数据指针的类比有些不太准确。即使它实际上指向未知大小的“派生”对象,我们仍然可以取消引用Base * - MSalters
3个回答

20

指针相当于一张盲文写有街道地址的纸条。

当您对其进行引用时,您将其交给一个盲人走到那个地方。除非告诉他们,否则这位盲人不知道那里是否有坑、房子、河流或购物中心:告诉他们是指针的类型

几乎所有地址都具有相同的长度。

当您知道指针是指向int时,您就是在告诉那位盲人在该地址处期望找到一个int。所以他们走到那里并与任何东西交互,就好像它是一个int

当您知道指针是一个函数指针,并且你对其进行了引用并调用它,那么这位盲人就不需要知道函数有多大:他只需要知道它从哪里开始。函数有点像游乐园里的设施——你上了车,然后在某个时刻他们让你下车。几乎总是让你从你上车的地方下车,少了口袋里掉落的东西,还带着一张纪念照片(返回值)。 (发生的确切情况将取决于调用约定)

现在,函数的签名很重要——它告诉您游乐设施期望乘客携带什么。返回值类型也很重要,因为它告诉您纪念照片的形状。但是函数的确切大小并不重要。

当然,我们还可以谈论成员函数指针、近指针、远指针、引用和其他更玄奥的事物。


哇,喜欢这个答案。 - user3358627
太好了。为修改其参数的函数添加类比 :p - Alma Do
@almado这个比喻最终会失效。但是嘉年华工人可以搜你的口袋,在上车时找到一些有地址的纸条,并在你坐着玩耍时将数据传递给那些地址。当然,这些快递员是瞎子。 - Yakk - Adam Nevraumont

2

很好的问题。在此之前我也有同样的疑问。函数指针与其他指针一样大,唯一的区别在于函数指针指向内存中的文本部分。每次进行方法调用时,计算机会解引用作为方法名称的函数指针。


但是我们不知道它的长度,就像空指针一样,我们知道它的地址,但我们真的不知道要读取多少字节... - user3358627
1
你不需要知道具体细节,只需要知道地址长度为4个字节。我们并没有使用指针来保存整个数据结构,而是对象的地址。函数已经被编译器预加载,你只需要有地址,这样你的程序就知道在代码中的哪个位置加载该函数。因此,从技术上讲,你“确实”知道它占用了多少内存。希望这能帮到你。 - Moonhead
谢谢您的清晰解释,我现在明白了。 - user3358627
1
“函数指针和其他指针一样大”这种说法是错误的,没有保证,并且void*与任何函数指针都不兼容。 - user2249683
@DieterLücking:准确地说:ISO C++ 没有这样的保证,尽管 POSIX 和 Windows 都有。 - MSalters

0
在抽象层面上,“解引用”指的是将指针转换回所指向的内容。对于具体类型,所指向的内容的大小是相关的,但这由类型本身而不是指针决定。当您调用函数时,调用代码肯定不需要知道函数的大小,因此当您解引用函数指针时,您也不需要知道函数的大小。

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