Delphi 积分真常数的类型是什么?
我很抱歉问了一个非常基本的问题。考虑下面的例子:Delphi 积分真常数的类型是什么?,delphi,Delphi,我很抱歉问了一个非常基本的问题。考虑下面的例子: const c1 = 1; // Is this Byte or ShortInt? c2 = 1234; // Is this Word or Smallint? c3 = 123456; // Is this Cardinal or Integer? 读完这篇文章后,我可以得出结论,负值被解释为有符号,而正值被解释为无符号。但是,例如,123456(根据文档将其解释为Cardinal)也可以在Integer的上下文
const
c1 = 1; // Is this Byte or ShortInt?
c2 = 1234; // Is this Word or Smallint?
c3 = 123456; // Is this Cardinal or Integer?
读完这篇文章后,我可以得出结论,负值被解释为有符号,而正值被解释为无符号。但是,例如,123456(根据文档将其解释为
Cardinal
)也可以在Integer
的上下文中使用,我的意思是在计算中使用常量的Integer
变量中使用。因此,常量是否保证始终是基数
,因此必须将其转换为整数
?回答您的原始问题:
每个常量的数据类型是什么
它们或多或少是非类型化的,并且在使用它们时假定一种类型,如文字值。它们不占用空间,通常没有地址,除非它们必须(例如字符串、集合等)。你可以认为它们是“代表文字的符号”。它们可以与C中的简单定义(IOW,文本替换)或汇编程序中的立即值相比较。所以'C'
可以是AnsiChar
、WideChar
、AnsiString
、WideString
或UnicodeString
,甚至可以分配给PChar
、PWideChar
或panichar
。类型取决于分配给它的内容,就像,一个文本。整数值或浮点类型、集合类型等也一样
请注意,如果您要求,编译器(以及-IMO不正确-文档)将为您提供一个类型,通常是可以容纳它的最小整数类型,或者是浮点值的扩展
或双精度
,或者它所属的枚举或集合类型。但那是,除非你问
常量表达式中只能使用“非类型化”或true常量。类型化常量(占用实空间的IOW常量)就像你说的,或多或少像“不可变变量”(是的,我知道这是一个矛盾修饰法),IOW,它们有一个地址,一个类型,一个定义的大小,但它们不是,呃,变量或可变的(就像David说的,忘记可写的类型化常量)
我相信这里的一些人会完全不同意,但是,嘿,这就是我一直认为的真实常数,这种观点从未让我失望过
如何强制常量具有特定的数据类型?我的意思是除了类型化常量之外的另一种方式,如果我是对的,它实际上是常量变量
通过强制转换,可以为类型指定一个真常量:
const
Bla = UInt64(1234); // $0000000000001234
Doo = Cardinal(-1); // $FFFFFFFF
Duh = Shortint(rfReplaceAll);
不过,我认为您不能强制转换为一种浮点类型。此类强制转换通常是禁止的,对于常量也是如此(AFAIK,现在无法测试)
现在期待一些尖锐的评论或否决票。:-)
更新
因此,是否保证常量始终为基数,以便有必要将类型转换为整数
不需要石膏。无论如何,该类型并不总是Cardinal
,即使文档这么说(正如我所说,我认为他们错了)。Is只是就好像您在该位置使用了文本值123456
。你可以说,123456
也有一个类型,但实际上,假装它没有要容易得多。类型取决于上下文,它可能被编译为
MOV EAX,123456
MOV [TheVariable],EAX
如何解释取决于变量的类型。例如,如果您这样做:
MyDouble := 123456;
这并不意味着编译了基数
,必须进行到双精度
的转换。它直接编译为Double
值123456.0
。可能存在转换,但仅在编译器内部
因此,我想,不要再担心这些常量的类型了。Simple将它们视为表示文字的符号,并假设它们将获得您期望的类型。你很少会错。
证明
请看下面的代码:
const
CHi = 'Hello';
CInt = $1234;
CTInt: Word = $1234;
var
CVInt: Word = $1234;
procedure Test;
var
A: AnsiString;
U: UnicodeString;
I: Integer;
D, E, F: Double;
begin
A := CHi;
U := CHi;
I := CInt;
D := CInt;
E := CTInt;
F := CVInt;
Writeln(A, U, I, D); // Just to make this compile.
end;
而这个的拆卸,
Project44.dpr.25: A := CHi;
00419584 8D45FC lea eax,[ebp-$04]
00419587 BA40964100 mov edx,$00419640
0041958C E84BE0FEFF call @LStrLAsg
Project44.dpr.26: U := CHi;
00419591 8D45F8 lea eax,[ebp-$08]
00419594 BA54964100 mov edx,$00419654
00419599 E8A2DFFEFF call @UStrLAsg
Project44.dpr.27: I := CInt;
0041959E C745F434120000 mov [ebp-$0c],$00001234
Project44.dpr.28: D := CInt;
004195A5 33C0 xor eax,eax
004195A7 8945E8 mov [ebp-$18],eax
004195AA C745EC0034B240 mov [ebp-$14],$40b23400
Project44.dpr.29: E := CTInt;
004195B1 0FB705A0D54100 movzx eax,[$0041d5a0]
004195B8 8945D4 mov [ebp-$2c],eax
004195BB DB45D4 fild dword ptr [ebp-$2c]
004195BE DD5DE0 fstp qword ptr [ebp-$20]
004195C1 9B wait
Project44.dpr.30: F := CVInt;
004195C2 0FB705A2D54100 movzx eax,[$0041d5a2]
004195C9 8945D4 mov [ebp-$2c],eax
004195CC DB45D4 fild dword ptr [ebp-$2c]
004195CF DD5DD8 fstp qword ptr [ebp-$28]
004195D2 9B wait
如您所见,字符串常量的值在分配给AnsiString
或UnicodeString
时不相同。复制反汇编的数据部分并不容易,因此您必须在自己的Delphi IDE中进行检查,但在地址$0041961C
处,有一个文本解析(refcount-1)'Hello',而在地址$00419630
处,有一个文本解构'Hello'。这意味着常量被编译为上下文所需的类型,不再需要显式或隐式转换(即从UnicodeString
到AnsiString
,或从Word
到Double
)
还要注意的是,与true常量相反,类型化的常量确实需要转换代码。字作为movzx eax,[$0041d5a0]
加载,即从word
转换为DWord
,然后存储为DWord
,作为DWord
加载到FPU,然后存储为64位浮点值(Double
)。这是一个你看不到的转换,因为它对于真常数来说是不需要的
我知道有些人会说:“嗯,这是一辆破车,但编译器先将其转换为AnsiString。”在我看来,这就像是说:“汽车的原始车身是灰色的,但在出售(分配)之前,它必须被漆成绿色。”我宁愿说:“出售的汽车是绿色的,不管它是如何得到那种颜色的。”当然,文本和常量(IOW,在常量
部分中定义的符号)将具有默认类型,在查询时给出,并且不请求特定类型,但是出于所有实际目的,如果简单地将它们视为“带名称标签的文本”,而将不视为特定类型,则最简单,低a
if @CInt = nil then;
if @CTInt = nil then;
program SO32160057_overloads;
{$APPTYPE CONSOLE}
procedure foo(value: UInt8); overload;
begin
Writeln('UInt8');
end;
procedure foo(value: UInt16); overload;
begin
Writeln('UInt16');
end;
procedure foo(value: UInt32); overload;
begin
Writeln('UInt32');
end;
procedure foo(value: UInt64); overload;
begin
Writeln('UInt64');
end;
procedure foo(value: Int8); overload;
begin
Writeln('Int8');
end;
procedure foo(value: Int16); overload;
begin
Writeln('Int16');
end;
procedure foo(value: Int32); overload;
begin
Writeln('Int32');
end;
procedure foo(value: Int64); overload;
begin
Writeln('Int64');
end;
const
ZeroInt32 = Int32(0);
ZeroUInt16 = UInt16(0);
begin
foo(127);
foo(128);
foo(32767);
foo(32768);
foo(2147483647);
foo(2147483648);
foo(9223372036854775807);
foo(9223372036854775808);
foo(ZeroInt32);
foo(ZeroUInt16);
foo(UInt8(0));
end.
Int8
UInt8
Int16
UInt16
Int32
UInt32
Int64
UInt64
Int32
UInt16
UInt8
program SO32160057_comparisons;
var
Int8var: Int8 = 0;
Int16var: Int16 = 0;
Int32var: Int32 = 0;
begin
if Int8var < 127 then ;
if Int8var < 128 then ; // line 10
if Int8var < Int16(128) then ; // line 11
if Int16var < 32767 then ;
if Int16var < 32768 then ; // line 13
if Int16var < Int32(32768) then ; // line 14
if Int32var < 2147483647 then ;
if Int32var < 2147483648 then ; // line 16
if Int32var < Int64(2147483648) then ;
end.
(10): W1022 Comparison always evaluates to True
(10): W1023 Comparing signed and unsigned types - widened both operands
(11): W1022 Comparison always evaluates to True
(13): W1022 Comparison always evaluates to True
(13): W1023 Comparing signed and unsigned types - widened both operands
(14): W1022 Comparison always evaluates to True
(16): W1022 Comparison always evaluates to True
(16): W1023 Comparing signed and unsigned types - widened both operands
program SO32160057_123456;
var
UInt32var: UInt32 = 0;
begin
if UInt32var > 123456 then ; // line 7
if UInt32var > -123456 then ; // line 8
end.
(8): W1022 Comparison always evaluates to True
(8): W1023 Comparing signed and unsigned types - widened both operands