防止“组合有符号和无符号类型扩展了两个操作数”编译器警告

时间:2013-06-24 00:07:36

标签: delphi delphi-2010

此代码用于设置组件,产生编译器警告:

[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);

这可以以某种方式进行类型转换以防止编译器警告吗?

3 个答案:

答案 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;