问题
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 asInteger
- 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