2016-09-02 21 views
4

如果我編譯下面的代碼它給第1行的警告「未初始化變量」:分配給LTIME「價值從來沒有使用過」變爲

值從未使用*

但如果我刪除了這一行,我坐上2號線不同的警告:

變量LTIME可能尚未初始化

編譯器是否丟失了一些東西,或者我?

procedure TFormWebServices.RemoveOldReports; 
var 
    TSR  : TSearchRec; 
    I   : Integer; 
    lCutOff, 
    lTime  : Int64; 
    TSToDelete: TStringList; 
    S,Msg  : String; 
    E   : Exception; 
begin 
    lCutOff := DelphiToJavaDateTime(Now - cDefReportLifeMins/1440); 
    I := FindFirst(FReportDir + '*.pdf',0,TSR); 
    TSToDelete := TStringList.Create; 
    while I = 0 do 
    begin 
    if (TSR.Attr and faDirectory) = 0 then 
    begin 
     lTime := lCutOff;   // Line 1 
     try 
     lTime := StrToInt64(Copy(TSR.Name,1,pos('.',TSR.Name)-1)); 
     except 
     on E:Exception do lTime := lCutOff; 
     end; 
     if lTime < lCutOff then // Line 2 
     TSToDelete.Add(TSR.Name); 
    end; 
    I := FindNext(TSR); 
    end; 

這不是一個Why is the Compiler warning that variable may not be initialized?傻瓜,因爲我在異常分配lTime爲好。

+1

的可能的複製(HTTP://計算器。 com/questions/11554857/why-the-compiler-warning-that-variable-may-not-initialized) –

+1

它看起來確實是重複的。 –

+0

但是,真的,這裏不需要使用異常處理。 RTL爲此提供了一套'TryStrTo [x]'方法 - 比讓異常處理程序處理它更有效。 [TryStrToInt64文檔](http://docwiki.embarcadero.com/Libraries/en/System.SysUtils.TryStrToInt64) –

回答

7
lTime := lCutOff;  
try 
    lTime := StrToInt64(Copy(TSR.Name,1,pos('.',TSR.Name)-1)); 
except 
    on E:Exception do lTime := lCutOff; 
end; 
if lTime < lCutOff then 
    TSToDelete.Add(TSR.Name); 

編譯器是正確的,警告有關此代碼。當您在第一行分配lTime := lCutOff時,寫入該分配的值永遠不會被讀取。

但是,當你刪除代碼時,事情不太清晰。

try 
    lTime := StrToInt64(Copy(TSR.Name,1,pos('.',TSR.Name)-1)); 
except 
    on E:Exception do lTime := lCutOff; 
end; 
if lTime < lCutOff then 
    TSToDelete.Add(TSR.Name); 

有兩種情況考慮:一個異常沒有上調try/except塊內,或將引發異常那裏。

如果沒有例外,那麼很簡單,lTime被指定爲StrToInt64的結果,因此在讀取之前被初始化。

在引發異常時,lTime未在塊內初始化。接下來發生什麼?

  • 如果異常從Exception(不是強制性的),然後得出被抓住lTime被初始化。
  • 如果異常不是從Exception派生的,那麼它不會被捕獲,並且lTime永遠不會被讀取。

因此,編譯器可以推斷出所有這些,因此不會發出未初始化的變量警告。然而,不幸的是,編譯器並沒有對這種複雜性進行流程分析。我相信,它的邏輯運行是這樣的:

  1. 一個異常lTime之前提出的初始化,然後
  2. 的異常可能會被抓,在這種情況下
  3. 變量lTime然後閱讀,仍有可能未初始化。

在步驟2中,應該能夠認識到lTime已經初始化,但它不會執行這樣的分析。因此,雖然人們可能會爭辯說編譯器可以做得更好,但您必須接受這個作爲其分析算法的限制。

瞭解到我們有任務找到一種方法來編寫代碼並避免警告。我們不想壓制這些警告,我們只需要找到一種編寫代碼的方法,以便它既正確又無警告。

在我看來,前進的道路是認識到異常是在這裏使用的錯誤工具。這種轉換是失敗的正常行爲。您應該使用轉換函數編寫代碼,在失敗時不會引發異常。例如,你可以使用下列選項之一:

if TryStrToInt64(..., lTime) then 
    if lTime < lCutOff then 
    .... 
else 
    lTime := lCutoff; 

或者:[?爲什麼編譯器警告該變量可能不被初始化]

lTime := StrToInt64Def(..., lCutoff); 
if lTime < lCutOff then 
    .... 
+1

Delphi XE編譯器不會在此代碼上生成虛假警告''變量。可能尚未初始化'。 – kludg

-1

這是正確的行爲。第1行的值將永遠不會被使用,因爲在嘗試/除了您分配一個新值而不使用前一個值,因此警告。

如果您刪除您嘗試使用LTIME變量一試線外/ except塊可以沒有值實際設置LTIME

procedure TFormWebServices.RemoveOldReports; 
var 
    TSR  : TSearchRec; 
    I   : Integer; 
    lCutOff, 
    lTime  : Int64; 
    TSToDelete: TStringList; 
    S,Msg  : String; 
    E   : Exception; 
    begin 
    lCutOff := DelphiToJavaDateTime(Now - cDefReportLifeMins/1440); 
    I := FindFirst(FReportDir + '*.pdf',0,TSR); 
    TSToDelete := TStringList.Create; 
    while I = 0 do 
     begin 
     if (TSR.Attr and faDirectory) = 0 then 
      begin 
       lTime := lCutOff;   // Line 1 
       try 
        lTime :=  StrToInt64(Copy(TSR.Name,1,pos('.',TSR.Name)-1)); 
       except 
        on E:Exception do lTime := lCutOff; 
       end; 
       if lTime < lCutOff then // Line 2 
        TSToDelete.Add(TSR.Name); 
      end; 
     I := FindNext(TSR); 
     end; 

失敗你可以這樣做

procedure TFormWebServices.RemoveOldReports; 
var 
    TSR  : TSearchRec; 
    I   : Integer; 
    lCutOff, 
    lTime  : Int64; 
    TSToDelete: TStringList; 
    S,Msg  : String; 
    E   : Exception; 
    begin 
    lCutOff := DelphiToJavaDateTime(Now - cDefReportLifeMins/1440); 
    I := FindFirst(FReportDir + '*.pdf',0,TSR); 
    TSToDelete := TStringList.Create; 
    while I = 0 do 
     begin 
     if (TSR.Attr and faDirectory) = 0 then 
      begin 
       lTime := StrToInt64Def(Copy(TSR.Name,1,pos('.',TSR.Name)-1), lCutOff); 
       if lTime < lCutOff then  
        TSToDelete.Add(TSR.Name); 
      end; 
     I := FindNext(TSR); 
     end; 
+0

謝謝,我不知道還有一個StrToInt ** 64 ** Def –

+0

我不同意第2段。實際上沒有任何情況,當第1行被刪除時,在被初始化之前'lTime'可以被讀取。 –

+0

第2行警告僅在刪除第1行時發生。爲什麼這是不正確的? –