我们经常使用result的函数返回值,有谁能够从作用域,生命期,初始值等几个方面谈一下result。(50分)

to creation-zy:
说的好啊,如当头棒喝,醍醐灌顶!
 
多谢creation-zy兄指教,令小弟茅塞顿开,20多年白活了,不过请看看楼主的题目然后再发表言论还是比较好的!至于你F NO F,那就不是我的事情了!
 
to 一剑封喉兄:
楼主的题目看起来没有什么问题,但是,看看他随后给出的代码以及问题,就会发现整个
帖子都是建立在一个错误的观点及其派生命题之上的。

严格的说来,函数的返回值的传递方式,是随着函数的调用方式而不同的,Delphi默认的
register调用方式,返回值是放在EAX中的,但如果用stdcall等其它调用约定,情况又不一
样了。所以,除非我们要写汇编过程,否则就应该严格的按照规定,初始化、赋值,一点都
不能马虎。
在编码时,除了要考虑遵守规范之外,还要考虑诸如线程安全、资源释放责任划分等很多
问题,在类似没有初始化等非标准问题上实在不应该花时间。
 
creation-zy兄,多谢,比较在其他开发工具中,在声明变量后必须要赋初始值,否则编译都不能通过,而在DELPHI中就没有这样的功能,我以上的回答只是在叙述一个客观存在的事实,我想您是在阐述编码原则,而我是在说开发工具的功能而已,这谈不上什么冲突!
不过还是多谢您的指教!
 
这个技巧算不上是开发工具的内容,比如房子的窗户当然可能能够进来人,院子的围墙也能够进来,但是总不能把这个也算成围墙和窗户的功能.你知道什么时候墙头上会安装上玻璃.划伤了手就不值了.
要知道,绝大多数是后(如果有不是的,自然在那部分少数里),你我所做的,并不是在创造什么东西,还是按照规则才能玩好游戏.就如同法律不可能面面俱到,可是钻法律的空子并不是什么好的习惯.
存在未必合理(至少在这个方面.不讨论哲学问题).

如果非要讨论这样的问题.楼主可以先看看我的代码.单就楼主的代码而言,不过对AnsiString的引用计数和写复制以及当前版本的编译器对string类型返回值的一种处理方式罢了,除非你在开发相当深度的东东,否则依靠于特定编译器的特定实现,并且这种利用逻辑本身并没有前途的用法,这绝对不是一件好事情.楼主代码体现的问题并不是很容易想到的通常的看法 EAX SELF等等.不是这样.至少对AnsiString,不是这样,和调用方式也没有直接的关系
 
Another_eYes 分析得比较深入,听课。。。。
楼主所贴出的别人的那段代码,我私下里也测试了。的确是Result在其自运算之前没有赋初值造成的不确定值。所以在Result要做自运算时,要养成赋予初值的习惯,这样才不会出现不可预知的错误。
我们可以做这样的测试:
function TForm1.a : string
begin
Result := 'hello!';
end;

function TForm1.mytest(i:integer):string;
begin
result:=result+','+inttostr(i);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
i:integer;
abc:string;
begin
abc := a;//先调用另一个函数
for i:=1 to 6 do
begin
abc:=mytest(i);//再调用mytest()函数
end;
showmessage(abc);
end;
这时的结果应该显示成这样了吧?
hello!,1,2,3,4,5,6
函数mytest的result承接了函数a的result值为初值了!如果a 为其他函数时也会造成这种结果。。。。都是result的自运算没赋初值惹的祸!
 
这种现象(AnsiString),至少在D7当中,不是不确定性,而是比较确定的结果.但是利用这并不可取.所谓不确定性,只是对于不同版本编译器的实现不确定性.
 
高度同意zjan521的意见。经我测试,在D7下,没有看到任何异常现象,每次都是一样的结果!
 
creation-zy 在语言层面上说明了这样做的不可取。
Another_eYes 在实现的层面上说明了这样做没有意义。
如果没有说明白,我想我可以做一下补充,希望能让大家明白(其实我自己也不很明白)
这段代码很容易让人认为result继承了上次运算的结果。
其实都是编译器处理的结果,让人产生了错觉。
让我们修改一下代码,把 abc := mytest(i) 改为 mytest(i)
循环结束时再加一句 abc := mytest(7);
运行看看什么结果。
都是编译器处理造成的。
abc := mytest(i) 这一句,编译器将abc当作一个参数(姑且这样认为)传了进去。
而这个参数占用的寄存器刚好就是result。这里没有给result赋初值,所以一开始
的时候事实上相当于执行了这么一句: result := abc;
如果只执行mytest(i), 那么 result 其实也还是用了上次的结果,但是这个结果不
是abc,而是编译器分配的一个临时变量。 相当于执行了一个 reslut := tmpvalue
但是在最后作 abc := mytest(7)的时候,一开始又执行了 result := abc
我们可以再加一个memo,每次调用mytest时把result显示出来,这样会比较清楚。
好了,也许明白了。rseult的初始值取决于编译器。
不明白?
在showmessage(abc)前加一句abc := mytes(7);运行。
然后再把abc := mytes(7);改为abc := mytes(7)+'my god!!!';运行看看。
是不是很&*%^&$%*&?现在你还认为有确定性吗?
事实上,还有更多的写法,可以造成更多不确定的结果。

好了,我们已经看到了很多种不同的情况。但是我们能拿来做什么呢?

语言是用来交流的,程序语言也是如此。
如果需要,我们可以明确的传递一个参数,或者赋一个值,那样不是更清晰明了
吗?至少,在写代码的时候,我不需要去想,这该死的编译器到底会把什么东西
放到那个寄存器,把什么入栈,我又是如何去调用的?下一个版本的编译器是否
又会做出什么优化,会不会改变原来的方式?

让这些问题见鬼去吧。
 
谢谢大家参与。
 
分太少,随便分的,不要介意。
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
D
回复
0
查看
919
DelphiTeacher的专栏
D
D
回复
0
查看
2K
DelphiTeacher的专栏
D
D
回复
0
查看
2K
DelphiTeacher的专栏
D
顶部