如何在Delphi的array of const中识别Cardinal类型?
问题分析
Delphi 的 array of const 依赖 TVarRec 类型存储参数,但 TVarRec 的 VType 枚举中没有专门的 vtCardinal 类型。由于 Cardinal 和 Integer 是同内存大小的无符号/有符号整数,编译器会将 Cardinal 隐式转换为 Integer 存入 VInteger 字段,导致超过 Integer 最大值的 Cardinal 值被解析为负数。
解决方案
以下提供两种实用的解决方式:
方案1:修改 vtInteger 分支的处理逻辑
在现有 vtInteger 分支中,判断值是否为负数(对应超出 Integer 范围的 Cardinal 值),将其转换为 Cardinal 类型输出,无需修改调用代码:
{$APPTYPE CONSOLE} uses SysUtils; procedure GetSomething(const Input: array of const); var LIndex: Integer; begin for LIndex := Low(Input) to High(Input) do begin case Input[LIndex].VType of vtWideString: Writeln('WideString = ''', WideString(Input[LIndex].VWideChar), ''''); vtInt64: Writeln('Int64 = ', Input[LIndex].VInt64^); vtCurrency: Writeln('Currency = ', CurrToStr(Input[LIndex].VCurrency^)); vtInteger: begin if Input[LIndex].VInteger < 0 then Writeln('Cardinal = ', Cardinal(Input[LIndex].VInteger)) else Writeln('Integer = ', Input[LIndex].VInteger); end; vtBoolean: Writeln('Boolean = ', BoolToStr(Input[LIndex].VBoolean, True)); vtChar: Writeln('Char = ''', Input[LIndex].VChar, ''''); vtExtended: Writeln('Extended = ', FloatToStr(Input[LIndex].VExtended^)); vtString: Writeln('ShortString = ''', Input[LIndex].VString^, ''''); vtPChar: Writeln('PChar = ''', Input[LIndex].VPChar, ''''); vtAnsiString: Writeln('AnsiString = ''', Ansistring(Input[LIndex].VAnsiString), ''''); vtWideChar: Writeln('WideChar = ''', Input[LIndex].VWideChar, ''''); vtPWideChar: Writeln('PWideChar = ''', Input[LIndex].VPWideChar, ''''); vtUnicodeString : Writeln('UnicodeString = ''', string(Input[LIndex].VUnicodeString), ''''); else Writeln('Unsupported'); end; end; end; var x: cardinal; begin x := 3147483647; try GetSomething(['some string', 123, x, 'something else', 12.3, false]); except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; Readln; end.
输出结果:
UnicodeString = 'some string' Integer = 123 Cardinal = 3147483647 UnicodeString = 'something else' Extended = 12,3 Boolean = False
方案2:调用时显式转换为 Int64
将 Cardinal 值转换为 Int64 后传入,此时会被识别为 vtInt64 类型,在对应分支中处理为 Cardinal:
// 调用处修改 GetSomething(['some string', 123, Int64(x), 'something else', 12.3, false]); // GetSomething 中的 vtInt64 分支修改 vtInt64: begin if (Input[LIndex].VInt64^ >= 0) and (Input[LIndex].VInt64^ <= Cardinal(High(Integer)) + 1) then Writeln('Cardinal = ', Cardinal(Input[LIndex].VInt64^)) else Writeln('Int64 = ', Input[LIndex].VInt64^); end;
这种方式更适合需要明确区分 Int64 和 Cardinal 的场景。
内容的提问来源于stack exchange,提问作者HobitZlobny
相关产品推荐
相关产品推荐

