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

Bil*_*ill 4 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);
Run Code Online (Sandbox Code Playgroud)

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

Arn*_*hez 5

在你的情况下,ord()返回integer,所以必须明确地键入式浇铸cardinal,通过改变ord()cardinal()这样:

iPrecision := Max(50, 100 - (3 + 2 * cardinal(iActive and iInProximity)) * iRadius);
Run Code Online (Sandbox Code Playgroud)

你将摆脱警告,你的代码将几乎相同.


Dav*_*nan 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.
Run Code Online (Sandbox Code Playgroud)

我相信你会希望这个程序的输出是50.但事实并非如此.输出为4294962396.

发生的事情是你100-X在无符号的上下文中执行X>100.执行此操作时,您将获得整数溢出,结果是一个非常大的正值.由于您使用的是无符号算术,因此无法将此值视为负值,因为unsigned中没有负值.

当然,如果启用了溢出检查的编译器选项,则会遇到运行时错误.但即使这不是你想要的.获得所需答案的简单方法是使用带符号算术执行操作.

{$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.
Run Code Online (Sandbox Code Playgroud)

并且该程序产生50的期望输出.

如果由于某种原因,您需要将值存储回无符号变量,那么在计算之外执行此操作.由于上述原因,重要的是使用有符号值执行计算.

....
var
  Precision: Cardinal;
begin
  Precision := CalcPrecision(1000, True, True);
  Writeln(Precision);
  Readln;
end.
Run Code Online (Sandbox Code Playgroud)

当然,即使是使用带符号算术编写的输入值,也可以提出会超出计算量的输入值.但在实践中,你会发现这种输入极不可能.另一方面,当使用非常合理的输入数据执行无符号时,很容易使方程式跳闸.