function 傳回的值會出現 Access violation |
尚未結案
|
ayachan
一般會員 發表:7 回覆:8 積分:8 註冊:2004-04-03 發送簡訊給我 |
例:
procedure DoProcess; var vNumber: double; begin vNumber:=Calculate; (下面還有計算) end; function Calculate: double; var vResult: double begin (當然實際裡面是很多計算,計算出 vResult) Result:=vResult; end;類似這樣的程式, 會在「vNumber:=Calculate;」這一行出現 Access violation。 而這一段程式是在別的系統裡執行無誤的。 如果只執行 Calculate; 不會錯誤。 Calculate 裡的 vResult 值是 double,沒有任何錯誤。 只要一執行 vNumber:=Calculate;,用 Watch Window 來看 vNumber 的值, 會發現從 0 變成 -NAN,然後就 Access violation 了。 請問為什麼會發生這個狀況,要怎樣解決呢? 先謝謝熱心回答的前輩了。 |
yyu10
中階會員 發表:9 回覆:99 積分:96 註冊:2005-02-18 發送簡訊給我 |
引言: 如果只執行 Calculate; 不會錯誤。如果在Delphi的设置中选择了优化代码, Delphi在Compile时会Ignore这行代码, 因为它不发挥任何任何作用. 即使Calculate存在runtime錯誤也不会表现出来. 引言: 會在「vNumber:=Calculate;」這一行出現 Access violation。錯誤很可能发生在 Calculate 里. 保留 vNumber:=Calculate, 然后在 Result:=vResult 处加个break point, 试试能否运行到这个reak point. 如果不能, 可以确定Calculate有问题. 如果能, ..... 思考中 ...... |
yorkland
高階會員 發表:2 回覆:138 積分:108 註冊:2004-12-17 發送簡訊給我 |
function Calculate: double; var vResult: double // 這是Local變數 begin (當然實際裡面是很多計算,計算出 vResult) Result:=vResult; // 當回傳資料時, vResult已經被Free掉了。 end; 建議寫法.. procedure DoProcess; var vNumber: double; begin Calculate(vNumber); (下面還有計算) end; function Calculate(var vResult: Double): Boolean; begin // 因為宣告成var的傳址方式, 在子程式段可以直接改寫變數的值。 // 善用var的方式, 把變數的宣告放在上層, 可避開不知何時Free的問題。 end; |
mustapha.wang
資深會員 發表:89 回覆:409 積分:274 註冊:2002-03-13 發送簡訊給我 |
|
yyu10
中階會員 發表:9 回覆:99 積分:96 註冊:2005-02-18 發送簡訊給我 |
|
ayachan
一般會員 發表:7 回覆:8 積分:8 註冊:2004-04-03 發送簡訊給我 |
|
yyu10
中階會員 發表:9 回覆:99 積分:96 註冊:2005-02-18 發送簡訊給我 |
|
ayachan
一般會員 發表:7 回覆:8 積分:8 註冊:2004-04-03 發送簡訊給我 |
function CalFactor:double; var CashRate: double; DORate: double; FixFactor,varValue: double; varDx: double; i,j:integer; varDxArray:array[0..110] of double; varNxArray:array[0..110] of double; varD,varLD: double; begin FillChar(varDxArray,SizeOf(varDxArray),#0); FillChar(varNxArray,SizeOf(varNxArray),#0); doRate:= MRate/100; CashRate:= 1/(1 DoRate); varD:=1-(CashRate); for i:=Age to High(Lx[0]) do begin varValue:= Power(CashRate,i); varDxArray[i]:=varValue*Lx[Sex,i]; end; for i:=Age to High(Lx[0]) do begin varDx:=0; for j:=i to High(Lx[0]) do varDx:=varDx varDxArray[j]; varNxArray[i]:=varDx; end; varLD:= POWER(CashRate,PromiseYear); FixAnnFactor:=varNxArray[RetireAge PromiseYear]/varDxArray[RetireAge] (1-varLD)/varD; Result:=FixFactor; end;Age、Sex、PromiseYear 等都是全域變數 Lx 是 array[0..1,0..110] of double |
yyu10
中階會員 發表:9 回覆:99 積分:96 註冊:2005-02-18 發送簡訊給我 |
|
ayachan
一般會員 發表:7 回覆:8 積分:8 註冊:2004-04-03 發送簡訊給我 |
|
yorkland
高階會員 發表:2 回覆:138 積分:108 註冊:2004-12-17 發送簡訊給我 |
|
yyu10
中階會員 發表:9 回覆:99 積分:96 註冊:2005-02-18 發送簡訊給我 |
|
ayachan
一般會員 發表:7 回覆:8 積分:8 註冊:2004-04-03 發送簡訊給我 |
FixFactor 是倒數第三行那邊給值的,貼上來時不小心打成 FixAnnFactor,已修正。 在 CalFactor 裡,所有的數值(包括 FixFactor 的值)都可以正常運算出來,不會有任何的錯誤。
Rate:=0.02; AccountTValue:=inValue; for i:=0 to (RetireAge-Age-1) do // 以複利計算 begin AccountTValue:=(AccountTValue-1500); AccountTValue:=(AccountTValue*Rate); end; //===原先在另一個程式可以執行不會出錯,可是在這就會Access Violation AnnVal:=CalFactor; // 錯在這一行, // 一把 CalFactor 的值 Assign 給 AnnVal, // AnnVal 就會變成-NAN,然後就 Access Violation 了。 tmpAnnVal:=AnnVal; AnnVal:=AccountTValue/AnnVal; //========================================================= if ((AnnVal>1200000)or(AnnVal<10000)) then begin if (AnnVal>1200000) then AnnVal:=1200000 else AnnVal:=0; SValue:=tmpAnnVal; // 另記錄下來顯示用 end else AnnVal=PayBack; for i:=(RetireAge-Age-1) to (110-Age) do tmpAry[i]:=AnnVal; // 顯示用 |
yyu10
中階會員 發表:9 回覆:99 積分:96 註冊:2005-02-18 發送簡訊給我 |
程式没有明显的错误. 这个问题有趣的地方在于, 程式中没有用到通常可能引起 A.V. 的东西, 比如 poiter, dynamic array , object, etc.
另外一种可能引起 A.V. 的原因是 stack corrupted. Stack pointer 和 base pointer 在 function call 后回不到该回的位置, 也会引起 A.V. 不过直接测试很麻烦, 需要在 CPU View 里观察 stack 在 call 前后的变化, 一两句话说不清楚. 还是先试试比较笨拙的办法吧, 下面是一个比较系统的测试计划, 一步一步的做. Step 1:
//AnnVal:=CalFactor;
AnnVal:= 1234; Step 2: 在 CalFactor 之前加个新function. function FakeCalFactor: double;
begin
Result := 1234;
end; 然后, //AnnVal:=CalFactor;
AnnVal:= FakeCalFactor; ****************************************
1和2是用来确认DoProcess没有问题.
**************************************** Step 3: 将 CalFactor 中Var部分Copy到 FakeCalFacotr, 测试一次. Step 4: 将 CalFactor 中的代码逐行Copy到 FakeCalFacotr的 Result := 1234 之前, 每Copy一行测试一次, 直到出现A.V.时停下来. Loop作为一个整体看待. ****************************************
在做所有测试之前, 请先检查一下Compiler的选项 Project -> Options -> Compiler: Code Generation:
Optimazation (Unchecked)
Aligned Record Fields (Checked)
Stack frames (Checked)
Pentium-safe FDIV (Unchecked) Runtime errors:
All Checked Debugging:
All Checked except "Definitions Only". 然后 Build project(NOT Compile project).
**************************************** _________________________
Programming is a passion 發表人 - yyu10 於 2005/02/27 11:26:53
|
StrongLemon
高階會員 發表:10 回覆:166 積分:105 註冊:2004-04-18 發送簡訊給我 |
您好:我修正過後如下,試試看哪裡會出問題
function TForm1.CalFactor:double; var CashRate: double; DORate: double; FixFactor,varValue: double; varDx: double; i,j:integer; varDxArray:array[0..110] of double; varNxArray:array[0..110] of double; varD,varLD: double; begin try FillChar(varDxArray,SizeOf(varDxArray),#0); FillChar(varNxArray,SizeOf(varNxArray),#0); doRate:= MRate/100; CashRate:= 1/(1 DoRate); varD:=1-(CashRate); if (Sex in [0,1]) then begin for i:=Age to High(Lx[Sex]) do begin varValue:= Power(CashRate,i); varDxArray[i]:=varValue*Lx[Sex,i]; end; for i:=Age to High(Lx[Sex]) do begin varDx:=0; for j:=i to High(Lx[Sex]) do varDx:=varDx varDxArray[j]; varNxArray[i]:=varDx; end; end else Raise Exception.Create('Sex is error'); varLD:= POWER(CashRate,PromiseYear); if ((RetireAge>=0) and (RetireAge<=100)) and (varDxArray[RetireAge]>0) and (varD>0) then begin if ((RetireAge PromiseYear)<=High(varNxArray)) and (RetireAge<=High(varDxArray)) and ((RetireAge PromiseYear)>=0) and (RetireAge>=0) then FixFactor:=varNxArray[RetireAge PromiseYear]/varDxArray[RetireAge] (1-varLD)/varD else Raise Exception.Create('(RetireAge PromiseYear)>High(varNxArray) or ' 'RetireAge>High(varDxArray) ' '(RetireAge PromiseYear)<0' 'RetireAge<0 and RetireAge>110 error' ); end else FixFactor:=NAN; Result:=FixFactor; except On E:Exception do begin ShowMessage(E.Message); end; end; end; |
mustapha.wang
資深會員 發表:89 回覆:409 積分:274 註冊:2002-03-13 發送簡訊給我 |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |