之前一直使用的是Delphi 7,现在准备转向Delphi XE7,据说数据类型上有一些微小的调整,便想亲自验证一下,也顺便加深一下自己对Delphi数据类型的认识,毕竟之前仅仅是在用而从未考虑过类型在内存中的形态。
验证方法很简单,就是在控制台用Sizeof()把相应数据类型的字节数显示出来。源码如下:
program TypeSize;
{$APPTYPE CONSOLE}
uses
SysUtils;
type
Emnu = (one, two, three, four);
Range1 = $0..$FF;
Range2 = $0..$FFFF;
Range3 = $0..$FFFFFFFF;
arr1 = array of Byte;
arr2 = array[0..9] of Byte;
arr3 = array[0..9] of Integer;
rcd1 = record
end;
rcd2 = record
b: Byte;
end;
rcd3 = record
i: Integer;
end;
rcd4 = record
i: Integer;
j: Integer;
end;
rcd5 = record
b: Byte;
i: Integer;
end;
rcd6 = record
r: Real;
end;
rcd7 = record
r: Real;
i: Integer;
end;
obj1 = object
end;
obj2 = object
c: Char;
end;
obj3 = object
i: Integer;
o: obj2;
end;
begin
Writeln(' Type | Bytes');
Writeln('--------------------------------');
Writeln('AnsiChar = ', SizeOf(AnsiChar));
Writeln('WideChar = ', SizeOf(WideChar));
Writeln('Char = ', SizeOf(Char));
Writeln('Byte = ', SizeOf(Byte));
Writeln('ShortInt = ', SizeOf(ShortInt));
Writeln('SmallInt = ', SizeOf(SmallInt));
Writeln('LongInt = ', SizeOf(LongInt));
Writeln('Int64 = ', SizeOf(Int64));
Writeln('Byte = ', SizeOf(Byte));
Writeln('Word = ', SizeOf(Word));
Writeln('LongWord = ', SizeOf(LongWord));
Writeln('Integer = ', SizeOf(Integer));
Writeln('Cardinal = ', SizeOf(Cardinal));
Writeln('Boolean = ', SizeOf(Boolean));
Writeln('ByteBool = ', SizeOf(ByteBool));
Writeln('WordBool = ', SizeOf(WordBool));
Writeln('LongBool = ', SizeOf(LongBool));
Writeln('Single = ', SizeOf(Single));
Writeln('Real48 = ', SizeOf(Real48));
Writeln('Double = ', SizeOf(Double));
Writeln('Extended = ', SizeOf(Extended));
Writeln('Comp = ', SizeOf(Comp));
Writeln('Currency = ', SizeOf(Currency));
Writeln('Real = ', SizeOf(Real));
Writeln('ShortString = ', SizeOf(ShortString));
Writeln('AnsiString = ', SizeOf(AnsiString));
Writeln('WideString = ', SizeOf(WideString));
Writeln('String = ', SizeOf(string));
Writeln('Variant = ', SizeOf(Variant));
Writeln('Pointer = ', SizeOf(Pointer));
Writeln('--------------------------------');
Writeln('Emnu = ', SizeOf(Emnu));
Writeln('Range(0,FF) = ', SizeOf(Range1));
Writeln('Range(0,FFFF) = ', SizeOf(Range2));
Writeln('Range(0,FFFFFFFF) = ', SizeOf(Range3));
Writeln('Array() = ', SizeOf(arr1));
Writeln('Array(10)Byte = ', SizeOf(arr2));
Writeln('Array(10)Int = ', SizeOf(arr3));
Writeln('Record() = ', SizeOf(rcd1));
Writeln('Record(1 byte) = ', SizeOf(rcd2));
Writeln('Record(1 int) = ', SizeOf(rcd3));
Writeln('Record(2 int) = ', SizeOf(rcd4));
Writeln('Record(1 byte, 1 int) = ', SizeOf(rcd5));
Writeln('Record(1 real) = ', SizeOf(rcd6));
Writeln('Record(1 real, 1 int) = ', SizeOf(rcd7));
Writeln('Object() = ', SizeOf(obj1));
Writeln('Object(1 char) = ', SizeOf(obj2));
Writeln('Object(1 int, 1 obj(char)) = ', SizeOf(obj3));
Readln;
end.
分别用Delphi 7和Delphi XE7编译,运行结果如图:
从运行结果可以看出:
- Delphi 7 和 Delphi XE7 数据类型的唯一区别就是默认的字符集发生的变化,Delphi 7 中 Char = AnsiChar,Delphi XE7 中Char = WideChar,即 Delphi 7 默认使用 ANSI 编码,Delphi XE7 默认使用 Unicode 编码。相应的,Delphi XE7 中 String = WideString,PChar = PWideChar。
- AnsiString、WideString、String 和 Pointer 一样占用 4B 的空间,说明,字符串类型的本质其实就是指针。由于 Delphi 对字符封闭得很好,使用起来感觉和整型、浮点型等没有什么差别,但毕竟还是不一样的,这是需要注意的(有关情况我会在另一篇中详细说明)。
- 枚举类型4个元素占1B,其它数量时也是1B,说明枚举类型实际存储的是元素的索引,或者说枚举类型的元素实际是对应索引值的一个别名。至于超过256个元素的情况未进行测试,即枚举类型元素上限未测。
- 子界类型与枚举类型比较类似,当元素个数少于256时用1B存储,超过256个时用2B,2B不够时用4B(没有3B的情况),以此推测,4B不够时将用8B、16B等。
- 静态数组占用的是连续的内存区域,其大小为数组元素大小的总合;动态数组在未指定数组大小时只有4B,说明动态数组的本质也是指针(有关细节会同字符串一同说明)。
- 记录类型的大小一般来说是其元素类型的大小*元素的个数,无元素时0B;如果元素类型不一致,元素类型统一按较大的类型的大小进行存储(猜想是为了方便寻址,拿空间换时间,提高运行速度)。
- Object类型是Delphi较早的一种类型,与记录类型很类似,不同的是其占用空间的大小为其元素大小的总合。估计Object类型就是记录类型的前身,而在记录类型出现后也依然没有消亡,想必仅仅是为了兼容古老的程序吧。