char[] annoyance...
Regan Heath
regan at netwin.co.nz
Mon Apr 10 15:33:54 PDT 2006
On Mon, 10 Apr 2006 16:28:00 +0000 (UTC), Kevin Bealer
<Kevin_member at pathlink.com> wrote:
> In article <ops7rncsol23k2f5 at nrage.netwin.co.nz>, Regan Heath says...
>>
>> Take this code:
>>
>> void main()
>> {
>> //..open a file, read line for line, on each line:
>>
>> for(int i = 0; i < line.length-2; i++) {
>> if (line[i..i+2] != "||") continue;
>> //..etc..
>> }
>> }
>>
>>
>> There is a subtle bug. On all lines with a length of 0 or 1 it will give
>> the following error:
>>
>> Error: ArrayBoundsError line_length.d(6)
>>
>>
>> The problem is of course the statement "i < line.length-2". line.length
>> is
>> unsigned, and when you - 2 from an unsigned value.. well lets just say
>> that it's bigger than the actual length of the line - 2.
>>
>>
>> Of course there are plently of other ways to code this, perhaps using
>> foreach, but that's not the point. The point is that this code _can_ be
>> written and on the surface looks fine. Not even -w (warnings) spots the
>> signed/unsigned problem. At the very least can we get a warning for
>> this?
>>
>> Regan
>
> I see the "gotcha" here, and whether conversions should be done is an
> interesting question. But I wanted to propose a slightly different
> solution.
>
>> for(int i = 0; i+2 < line.length; i++) {
>
> Since you are reference "i+2" in the expression, that is really the
> value what you need to be in the [0..length) range.
You're probably right.. now, if only I could train my brain to think of it
that way round :)
> More generally, always do the arithmetic with the signed variables in
> cases like this if there is a possibility of wraparound.
That's good advice, however you have to realise there is a possibility of
wraparound, something I didn't do (or I wouldn't have had the problem in
the first place) :(
> But if the automatic conversions were specified to do uint->int that
> would also be fine with me.
But wouldn't that introduce a bug here:
int a = int.max-1;
uint b = int.max+1;
assert(a < b);
wouldn't b be promoted to a signed value of <some negative number>?
> One can also imagine a language with the following inequalities:
>
> +> unsigned greater-than
> +< unsigned less than
> -> signed greater than
> -< signed less than
> +>= unsigned greater-or-equal
> etc
>
> This would not replace the current >, <, but would essentially just be
> shorthand for existing expressions:
>
> (A +> B) is the same as (cast(uint)A > cast(uint)B)
>
> .. and so on, except that uint, ulong, ushort, etc would be chosen as
> needed.
>
> Is this worth doing? Maybe - it's not a big deal to me, but the
> signed/unsigned question does represent a common gotcha in certain
> expressions.
It's a good idea, but, same problem as before; you have to realise length
is signed and you have to realise there is a chance for wraparound. A
warning about the signed/unsigned comparrison is the very least we should
do. I would be tempted to even make it an outright error requiring a cast
(or one of these new operators above) to handle.
Regan
More information about the Digitalmars-d
mailing list