2012-10-11 1 views
5

델파이 6에서 오류없이 컴파일되고 실행되는 코드를 생각해보십시오. sa의 빈 배열을 보는 대신 동적 문자열 배열을 복구 할 때 길이가 1 인 배열을 볼 수 있습니다. 빈 문자열. 왜 이렇게하고 어떻게 NIL 동적 배열을 Variant에 안전하게 할당하고 올바르게 복구 할 수 있습니까? 코드는 다음과 같습니다.Variant에 NIL 배열을 할당하면 왜 비어 있지 않은 배열이 Delphi 6에서 반환됩니까?

TDynamicStringArray = array of string; 

var 
    V: Variant; 
    sa: TDynamicStringArray; 
begin 
    sa := nil; 

    V := sa; 

    sa := V; 

    OutputDebugString('sa has a single element now with an empty string in it when I expect it to be empty.'); 
end; 
+0

아마도 타입 변환은 'variant -> pointer -> 문자열 배열'대신에 'variant -> string -> array of arrays'입니다. –

답변

5

두 가지 버그가 있습니다.

우선 Variants.DynArrayVariantBounds. 동적 배열이 nil 일 때이 오류는 (0, 0)의 낮은/높은 경계 쌍을 잘못 반환합니다. (0, -1)을 반환해야합니다. 이 버그는 최신 버전의 Delphi에서 수정되었습니다. 이로 인해 V := sa은 하나의 빈 요소가있는 변형 배열을 반환합니다.

두 번째 버그는 다른 방향 인 sa := V에 영향을줍니다. 이 버그는 최신 버전의 Delphi에서 계속 나타납니다. 이 버그는 Variants.DynArrayFromVariant에 있습니다. repeat/until 루프가 입력 변형 배열을 거쳐 출력 동적 배열을 채 웁니다. 입력 변형 배열이 비어있는 경우 해당 배열에 repeat/until 루프를 입력하면 안됩니다. 그러나이 코드는 실수로 VarArrayGet을 사용하여 변형 배열의 요소를 읽으려고 시도합니다. 배열이 비어 있기 때문에 런타임 오류가 발생합니다. 나는 이것을보고했다 : QC#109445.

다음은 버그를 수정하는 매우 간단한 코드입니다. 배열이 1 차원 인 경우만을 고려해야합니다. 고 차원 배열을 지원해야하는 경우이 방법을 확장하여 그렇게 할 수 있습니다.

program Project1; 

{$APPTYPE CONSOLE} 

uses 
    Variants; 

var 
    OriginalVarFromDynArray: procedure(var V: Variant; const DynArray: Pointer; TypeInfo: Pointer); 
    OriginalVarToDynArray: procedure(var DynArray: Pointer; const V: Variant; TypeInfo: Pointer); 

function DynArrayVarType(typeInfo: PDynArrayTypeInfo): Integer; 
const 
    tkDynArray = 17; 
begin 
    Result := varNull; 
    if (typeInfo<>nil) and (typeInfo.Kind=tkDynArray) then 
    begin 
    Inc(PChar(typeInfo), Length(typeInfo.name)); 
    Result := typeInfo.varType; 
    if Result=$48 then 
     Result := varString; 
    end; 
    if (Result<=varNull) or (Result=$000E) or (Result=$000F) or ((Result>varInt64) and not (Result=varString)) then 
    VarCastError; 
end; 

procedure VarFromDynArray(var V: Variant; const DynArray: Pointer; TypeInfo: Pointer); 
var 
    VarType, DynDim: Integer; 
begin 
    DynDim := DynarrayDim(PDynArrayTypeInfo(TypeInfo)); 
    if DynDim=1 then 
    begin 
    //only attempt to deal with 1 dimensional arrays 
    if DynArray=nil then begin 
     VarClear(V); 
     VarType := DynArrayVarType(PDynArrayTypeInfo(TypeInfo)); 
     if VarType = varString then 
     VarType := varOleStr; 
     V := VarArrayCreate([0, -1], VarType); 
     exit; 
    end; 
    end; 
    OriginalVarFromDynArray(V, DynArray, TypeInfo); 
end; 

procedure VarToDynArray(var DynArray: Pointer; const V: Variant; TypeInfo: Pointer); 
var 
    DimCount: Integer; 
    Len: Integer; 
begin 
    DimCount:= VarArrayDimCount(V); 
    if DimCount=1 then 
    begin 
    //only attempt to deal with 1 dimensional arrays 
    Len := VarArrayHighBound(V, 1) - VarArrayLowBound(V, 1) + 1; 
    if Len=0 then begin 
     DynArraySetLength(DynArray, PDynArrayTypeInfo(TypeInfo), 1, @Len); 
     exit; 
    end; 
    end; 
    OriginalVarToDynArray(DynArray, V, TypeInfo); 
end; 

procedure FixVariants; 
var 
    VarMgr: TVariantManager; 
begin 
    GetVariantManager(VarMgr); 
    OriginalVarFromDynArray := VarMgr.VarFromDynArray; 
    VarMgr.VarFromDynArray := VarFromDynArray; 
    OriginalVarToDynArray := VarMgr.VarToDynArray; 
    VarMgr.VarToDynArray := VarToDynArray; 
    SetVariantManager(VarMgr); 
end; 

type 
    TDynamicStringArray = array of string; 

var 
    V: Variant; 
    sa: TDynamicStringArray; 
begin 
    FixVariants; 

    sa := nil; 
    V := sa; 
    sa := V; 

    Writeln(Length(sa)); 
    Readln; 
end. 
+0

감사합니다. 그것은 정말 큰 버그입니다. –

관련 문제