此代码用于设置组件,产生编译器警告:
[DCC Warning] Unit1.pas(742): W1024 Combining signed and unsigned types - widened both operands
var
iPrecision: cardinal;
iRadius: cardinal;
iActive: boolean;
iInProximity: boolean;
iPrecision := Max(50, 100 - (3 + 2 * ord(iActive and iInProximity)) * iRadius);
这可以以某种方式进行类型转换以防止编译器警告吗?
答案 0 :(得分:5)
在您的情况下,ord()
会返回integer
,因此需要通过将cardinal
更改为ord()
来明确地类型转换为cardinal()
:
iPrecision := Max(50, 100 - (3 + 2 * cardinal(iActive and iInProximity)) * iRadius);
你将摆脱警告,你的代码几乎是一样的。
答案 1 :(得分:5)
Arnaud解释说ord()
返回一个签名值,这是警告的来源。 Arnaud和Ken都建议如何通过避免使用无符号操作数来删除警告。
我想提供另一种意见,并建议您选择使用已签名的操作数。假设您仅使用带符号的操作数执行计算。请考虑以下程序:
{$APPTYPE CONSOLE}
uses
Math;
function CalcPrecision(Radius: cardinal; Active, InProximity: boolean): Cardinal;
begin
Result := Max(50, 100-(3+2*Cardinal(Active and InProximity))*Radius);
end;
begin
Writeln(CalcPrecision(1000, True, True));
Readln;
end.
我确信你会希望这个程序的输出为50.但事实并非如此。输出为4294962396。
在100-X
的无签名上下文中执行X>100
会发生什么。执行此操作时,您将获得整数溢出,结果是一个非常大的正值。由于您使用无符号算术,因此在无符号时没有负值,因此您不能指望它为负值。
当然,如果启用了溢出检查的编译器选项,则会遇到运行时错误。但即使这不是你想要的。获得所需答案的简单方法是使用带符号算术执行操作。
{$APPTYPE CONSOLE}
uses
Math;
function CalcPrecision(Radius: Integer; Active, InProximity: boolean): Integer;
begin
Result := Max(50, 100-(3+2*ord(Active and InProximity))*Radius);
end;
begin
Writeln(CalcPrecision(1000, True, True));
Readln;
end.
此程序产生50的所需输出。
如果由于某种原因,您需要将值存储回无符号变量,那么在计算之外执行此操作。由于上述原因,使用有符号值执行计算非常重要。
....
var
Precision: Cardinal;
begin
Precision := CalcPrecision(1000, True, True);
Writeln(Precision);
Readln;
end.
当然,即使使用带符号算术编写,也可以提出会超出计算量的输入值。但实际上你会发现这种输入极不可能。另一方面,当使用非常合理的输入数据执行无符号时,很容易使方程式跳闸。
答案 2 :(得分:1)
您可以通过
避免编译器警告Cardinal
变量更改为签名类型,例如Integer
var ... const BoolValues: array[Boolean] of Cardinal = (0, 1); begin ... iPrecision := Max(50, 100 - (3 + 2 * BoolValues[iActive and iInProximity]) * iRadius); end;