Prevention of "combining signed and unsigned extended types of both operands" compiler warning

This code, which is used to install the component, generates 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); 

Could this be somehow to prevent a compiler warning?

+4
source share
3 answers

In your case, ord() returns an integer , so you need to explicitly inject it into the cardinal type, changing ord() to cardinal() as follows:

 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.

+4
source

Arno explained that ord() returns a signed value, which is the source of the warning. Both Arno and Ken suggested removing the warning, avoiding the use of unsigned operands.

I would like to offer an alternative opinion and suggest you use signed operands instead. Suppose you perform a 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 am sure that you hope that the output of this program will be 50. This is not so. The output signal is 4294962396.

It happens that you execute 100-X in an unsigned context, where X>100 . When you do this, you have an integer overflow, and the result will be a very large positive value. Since you are using unsigned arithmetic, you cannot expect this to be a negative value because unsigned does not have negative values.

Of course, if the compiler option for checking overflow was turned on, you ran into an error at runtime. But even that is not what you want. An easy 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 result 50.

If for some reason you need to save the value back to an unsigned variable, then do it outside of the calculation. This is important for the reasons illustrated above, that the calculation is performed with signed signs.

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

Of course, it is true that you can come up with input values ​​that will overwhelm the calculation, even if it is written using signed arithmetic. But in practice, you will find that such input is extremely unlikely. On the other hand, it is very easy to turn off your equation when it is unsigned using fairly reasonable input.

+5
source

You can avoid the compiler warning with

  • Changing Cardinal variables to a signed type, for example Integer
  • Use a small 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;

+1
source

Source: https://habr.com/ru/post/1487779/


All Articles