Preventing “combining signed and unsigned types widened both operands” compiler warning

一世执手 提交于 2020-01-14 12:20:08

问题


This code, which is used to setup a component, produces a compiler warning:

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

Can this be typecast somehow to prevent a compiler warning?


回答1:


In your case, ord() returns an integer, so needs to be explicitely type-casted to cardinal, by changing ord() into cardinal() as such:

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

You will get rid of the warning, and your code will be almost the same.




回答2:


Arnaud has explained that ord() returns a signed value which is the source of the warning. Both Arnaud and Ken have suggested how to remove the warning by avoiding the use of unsigned operands.

I would like to offer an alternative opinion and suggest that you instead choose to use signed operands. Let's suppose that you perform the calculation using only signed operands. Consider the following program:

{$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.

I'm sure that you would hope that the output of this program would be 50. It's not. The output is 4294962396.

What happens is that you perform 100-X in an unsigned context where X>100. When you do this you have integer overflow and the result is a very large positive value. Since you are using unsigned arithmetic, you cannot expect this to be a negative value because there are no negative values in unsigned.

Of course, if the compiler option for overflow checking was enabled, you would encounter a runtime error. But even that is not what you want. The simple way to get the answer you need is to perform the operation using signed arithmetic.

{$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.

And this program produces the desired output of 50.

If for some reason, you need to store the value back to an unsigned variable, then do that outside the calculation. It's important for the reasons illustrated above that the calculation is performed with signed values.

....
var
  Precision: Cardinal;
begin
  Precision := CalcPrecision(1000, True, True);
  Writeln(Precision);
  Readln;
end.

Of course, it's true that you can come up with input values that will overflow the calculation, even if it is written using signed arithmetic. But in practise you will find that such input is exceptionally unlikely. On the other hand, it's very easy to trip your equation up when it is performed unsigned, using quite reasonable input data.




回答3:


You can avoid the compiler warning by either

  • Changing your Cardinal variables to a signed type such as Integer
  • Use a slight workaround like this:
var
  ...
const
  BoolValues: array[Boolean] of Cardinal = (0, 1);
begin
  ...
  iPrecision := Max(50, 100 - (3 + 2 * BoolValues[iActive and iInProximity]) * iRadius);
end;



来源:https://stackoverflow.com/questions/17266462/preventing-combining-signed-and-unsigned-types-widened-both-operands-compiler

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!