Is this reasonable?

H. S. Teoh hsteoh at quickfur.ath.cx
Thu Dec 5 09:42:47 PST 2013


On Thu, Dec 05, 2013 at 06:15:37PM +0100, Steve Teale wrote:
> Here I feel like a beginner, but it seems very unfriendly:
> 
> import std.stdio;
> 
> struct ABC
> {
>    double a;
>    int b;
>    bool c;
> }
> 
> ABC[20] aabc;
> 
> void foo(int n)
> {
>    writefln("n: %d, aabc.length: %d", n, aabc.length);
>    if (n < aabc.length)
>       writeln("A");
>    else
>       writeln("B");
> }
> 
> void main(string[] args)
> {
>    int n = -1;
>    foo(n);
> }
> 
> This comes back with "B".
> 
> If I change the test to (n < cast(int) aabc.length), then all is
> well.
> 
> Is this unavoidable, or could the compiler safely make the
> conversion implicitly?

Comparing a signed value to an unsigned value is a risky operation. You
should always compare values of like signedness, otherwise you'll run
into problems like this.

You can't compare -1 to an unsigned value because if that unsigned value
happens to be uint.max, then there is no machine instruction that will
give the correct result (the compiler would have to substitute the code
with something like:

	uint y;
	if (x < 0 || cast(uint)x < y) { ... }

which will probably introduce undesirable overhead.

The compiler also can't automatically convert aabc.length to int,
because if the length is greater than int.max (which is half of
uint.max), the conversion would produce a wrong negative value instead,
and the comparison will fail.

So, comparing a signed value to an unsigned value is a dangerous,
error-prone operation.  Sadly, dmd doesn't warn about such risky
operations; it just silently casts the values. Bearophile has often
complained about this, and I'm starting to agree. This is one of the
places in D where subtle mistakes can creep in and the compiler fails to
warn the programmer of it.


T

-- 
Real Programmers use "cat > a.out".


More information about the Digitalmars-d-learn mailing list