Re: [问题] 函数指标

楼主: Feis (永远睡不着 @@)   2015-03-23 09:06:25
※ 引述《purpose (purpose)》之铭言:
→ Feis: 从标准的角度来看, 这些讲法不尽正确. C 跟 C++ 也不尽相同 03/22 21:14
→ jono103: 感谢p大回复 你的说法可以接受 但F大又说不一定正确@@? 03/23 00:10
→ jono103: 可以请F大赐教吗? 或给个方向或哪些书 非常感激 03/23 00:12
其实我也不太懂,尤其是对于 C++。不过就 C 的部份我可以稍微分享一下个人的理解。
int a[3];
就阵列来说,阵列名称本身的型别是阵列 (如上面宣告的 a 其型别是 "长度为 3 的
int 阵列")。
在 C 标准里面的规则是在运算时,除非做为 sizeof、取址 (&) 或 _AlignOf (C11)
的算子,或阵列本身为 register storage,其他运算一律被转为指向阵列第一个元素
的指标 (a 会转为 &a[0])。而这个指标不是一个左值 (换句话说是无法被赋值 (=) 的)
依照这个规则,造成我们常理解成:在 C 里面,一般情况下,阵列名称就是当作指向第
一个阵列元素的指标在 "用"。甚至因为它不是一个左值,有些人会说它是个常数。
而这边所指的一般情况甚至包含了我们最常用的阵列元素存取。
例如 a[2] 这个阵列元素存取的运算实际上会被转为 (&a[0])[2],而 (&a[0])[2] 会用
*(&a[0] + 2) 去解释。虽然就结果而言我们就是得到了 a 阵列的第三个元素,但是
就标准来说我们是透过指标运算去存取的。
这种种现象可能就是造成为什么书里面总是把阵列跟指标弄得一团乱的原因。
那函数呢 ?
void f();
C 标准里对于函数的企图在某些层面上跟阵列有点像,但是不幸的是函数本身更复杂。
就函数来说,函数名称本身的型别是函数 (如上面宣告的 f 其型别就是回传 void 型态
的函数)。
在 C 标准里面的规则是在运算时,除非做为 sizeof、取址 (&) 或 _AlignOf(C11)
的算子,其他运算一律转为指向函数的指标。而这个指标不是一个左值。
你看看,这不是跟阵列很像吗?
依照这个规则,造成我们常理解成:在 C 里面,一般情况下,函数名称就是当作指向
函数的指标在 "用"。甚至因为它不是一个左值,有些人会说它是个常数。
但是为什么上面这句听起来怪怪的,如果我们呼叫 f() 会发生什么事?
就标准而言就是会把 f 转型成 &f 然后呼叫指标所指向的函数。也就是说 f() 会变成
(&f)() 然后去呼叫 &f 所指向的函数 (阿不就是 f)。
换句话说,就 C 来说,存取阵列元素 ([]) 跟呼叫函数 (()) 概念上都是透过指标。
但是指向的东西本质上却有很大的不同。
这两者的差别最容易理解的应该就是 sizeof,因为不论阵列或函数名称都不会对他自动
转型,所以我们可以用来分辨其本质的不同。
sizeof(a) 是求阵列 a 所占据的空间大小,其结果就是整个阵列所占据的大小,相当和
蔼可亲。
那 sizeof(f) 呢?
C 标准跟我们说,"不可问、不可说"。对,这是个谜,而你不需要知道。
而阵列跟函数的指标运算还有一个很明显的不同:
*a 会转成 *(&a[0]) 去存取 a 阵列第一个元素
那 *f 呢?
照刚刚的规则会变成 *(&f) 然后变成 f,接着又会套用一次同样的规则,又变成 &f
所以就运算上 *a 跟 a 型态就已经不同,但是 *f == f 而且 *f == &f
更莫名的就是 f == **f 还有 f == *********f
至于 C++ 的话, 我只能跟你说两者在设计的哲学上就已经不一样. 但是我不懂 C++ 就
不好说什么
楼主: Feis (永远睡不着 @@)   2014-03-22 21:14:00
从标准的角度来看, 这些讲法不尽正确. C 跟 C++ 也不尽相同
作者: jono103 (不说对不起)   2014-03-23 00:10:00
感谢p大回复 你的说法可以接受 但F大又说不一定正确@@?可以请F大赐教吗? 或给个方向或哪些书 非常感激
作者: wenyonba (射后不理很XX啊!!!!)   2015-03-23 10:18:00
再推,多看点多学点,即使佛曰不可说不可说 XD
作者: MOONRAKER (㊣牛鹤鳗毛人)   2015-03-23 10:22:00
*_*********
作者: bibo9901 (function(){})()   2015-03-23 11:01:00
这样a[2]转为(&a[0])[2]后,会再转为 (&(a[0])[0])[2]吗
楼主: Feis (永远睡不着 @@)   2015-03-23 11:03:00
把 &a[0] 直接解释成阵列第一个元素的位址.在表达上我还没想到最好的写法.
作者: suhorng ( )   2015-03-23 12:33:00
最爱 std::function 跟微笑胡子算式 <:]{%> 了
作者: jono103 (不说对不起)   2015-03-23 12:50:00
感谢回复 学习了,也就是说 f *f &f type是一样的?是吗
作者: wenyonba (射后不理很XX啊!!!!)   2015-03-23 13:13:00
应该是说 f *f &f 行为一样,f 有 type,而讨论 *f &f 又是什么 type,基本上已经没啥意义了...我这样说对吗??
楼主: Feis (永远睡不着 @@)   2015-03-23 13:25:00
看来我确实表达不好. 严格来说 f 跟 *f 是一样的型态型别都是 "回传 void 型态的函数". C 标准这样的运算式名字叫 function designator. 这两者在作为一般运算的算子时会一律转型为 "指向回传 void 型态函数的指标"而 &f 就已经是指标了, 在做为一般运算的算子时不会再转型所以当上面用 == 运算来比较的时候会相等是因为比较时 f 跟*f 被转型跟 &f 一样了..
作者: james732 (好人超)   2015-03-23 15:17:00
推,之前还真没想得这么深入....
作者: jono103 (不说对不起)   2015-03-23 22:31:00
再次感谢。也就是说上上篇问题答案如下,有错请指正 3Q1."回传 void 型态的函数"自动转为"指向回传 void 型态函数的指标"2.fptr=max; 实际上为 fptr=(&max);3.type是一样 都是"回传 void 型态的函数"4.在fptr (*fptr)当函式呼叫时都自动转型为(&fptr)指标
作者: carylorrk (carylorrk)   2015-03-25 03:11:00
张辽,我的头又开始痛了
作者: HowLeeHi (处处留心皆正妹)   2015-04-05 16:29:00
还真没想过size(f)是什么鬼..@@不过a[2]我的理解是转成*(a+2)这样

Links booklink

Contact Us: admin [ a t ] ucptt.com