2016-09-02 18 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行时发生。为什么这是不正确的? –