www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Overflow-safe use of unsigned integral types

reply Joseph Rushton Wakeling <joseph.wakeling webdrake.net> writes:
One of the challenges when working with unsigned types is that automatic 
wraparound and implicit conversion can combine to unpleasant effect.

Consider e.g.:

     void foo(ulong n)
     {
         writeln(n);
     }

     void main()
     {
         foo(-3);
     }

... which will output: 18446744073709551613 (or, ulong.max + 1 - 3).

Is there a recommended way to handle this kind of potential wraparound where it 
is absolutely unacceptable?  I've considered the following trick:

     void bar(T : ulong)(T n)
     {
         static if (isSigned!T)
         {
             enforce(n >= 0);    // or assert, depending on your priorities
         }
         writeln(n);
     }

... but it would be nice if there was some kind of syntax sugar in place that 
would avoid such a verbose solution.

I know that there have been requests for runtime overflow detection that is on 
by default (bearophile?), but it could be good to have some simple way to 
indicate "really, no overflow" even where by default it's not provided.

(Motivation: suppose that you have some kind of function that takes a size_t
and 
uses that to determine an allocation.  If a negative number gets passed by 
accident, the function will thus try to allocate 2^64 - n elements, and your 
computer will have a very happy time...:-)
Nov 10 2013
next sibling parent reply "mike james" <foo bar.com> writes:
On Sunday, 10 November 2013 at 12:05:45 UTC, Joseph Rushton 
Wakeling wrote:
 One of the challenges when working with unsigned types is that 
 automatic wraparound and implicit conversion can combine to 
 unpleasant effect.

 Consider e.g.:

     void foo(ulong n)
     {
         writeln(n);
     }

     void main()
     {
         foo(-3);
     }

 ... which will output: 18446744073709551613 (or, ulong.max + 1 
 - 3).

 Is there a recommended way to handle this kind of potential 
 wraparound where it is absolutely unacceptable?  I've 
 considered the following trick:

     void bar(T : ulong)(T n)
     {
         static if (isSigned!T)
         {
             enforce(n >= 0);    // or assert, depending on your 
 priorities
         }
         writeln(n);
     }

 ... but it would be nice if there was some kind of syntax sugar 
 in place that would avoid such a verbose solution.

 I know that there have been requests for runtime overflow 
 detection that is on by default (bearophile?), but it could be 
 good to have some simple way to indicate "really, no overflow" 
 even where by default it's not provided.

 (Motivation: suppose that you have some kind of function that 
 takes a size_t and uses that to determine an allocation.  If a 
 negative number gets passed by accident, the function will thus 
 try to allocate 2^64 - n elements, and your computer will have 
 a very happy time...:-)
When writing software for embedded micros you can always check an overflow flag - is the no such mechanism on PC software? -=mike=-
Nov 10 2013
parent reply "rumbu" <rumbu rumbu.ro> writes:
On Sunday, 10 November 2013 at 12:19:18 UTC, mike james wrote:
 When writing software for embedded micros you can always check 
 an overflow flag - is the no such mechanism on PC software?
This is not overflow checking, it's the compiler considering a variable of type int implicitely convertible to equivalent unsigned types at bit level. I suppose it's a bug or may be the documentation is wrong (http://dlang.org/type.html): ubyte u1 = cast(byte)-1; // error, -1 cannot be represented in a ubyte ushort u2 = cast(short)-1; // error, -1 cannot be represented in a ushort These two lines are succesfully compiled by the last DMD on Windows.
Nov 10 2013
parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday, November 10, 2013 21:40:14 rumbu wrote:
 On Sunday, 10 November 2013 at 12:19:18 UTC, mike james wrote:
 When writing software for embedded micros you can always check
 an overflow flag - is the no such mechanism on PC software?
This is not overflow checking, it's the compiler considering a variable of type int implicitely convertible to equivalent unsigned types at bit level. I suppose it's a bug or may be the documentation is wrong (http://dlang.org/type.html): ubyte u1 = cast(byte)-1; // error, -1 cannot be represented in a ubyte ushort u2 = cast(short)-1; // error, -1 cannot be represented in a ushort These two lines are succesfully compiled by the last DMD on Windows.
Casts are never checked on integral types, so the documentation is outright wrong in this case: https://d.puremagic.com/issues/show_bug.cgi?id=11493 The only checks that are done with casts are 1. whether the compiler can convert from the original type to the requested type (which has nothing to do with the values of anything - just the types) 2. whether a class instance is actually of the type beng cast to (and if it isn't, the cast results in null) When you cast, you're generally telling the compiler that you know what you're doing and don't care what the compiler thinks about whether one value should be converted to the other just so long as the types can do the conversion. - Jonathan M Davis
Nov 10 2013
prev sibling parent reply luka8088 <luka8088 owave.net> writes:
On 10.11.2013. 12:10, Joseph Rushton Wakeling wrote:
 One of the challenges when working with unsigned types is that automatic
 wraparound and implicit conversion can combine to unpleasant effect.
 
 Consider e.g.:
 
     void foo(ulong n)
     {
         writeln(n);
     }
 
     void main()
     {
         foo(-3);
     }
 
 ... which will output: 18446744073709551613 (or, ulong.max + 1 - 3).
 
 Is there a recommended way to handle this kind of potential wraparound
 where it is absolutely unacceptable?  I've considered the following trick:
 
     void bar(T : ulong)(T n)
     {
         static if (isSigned!T)
         {
             enforce(n >= 0);    // or assert, depending on your priorities
         }
         writeln(n);
     }
 
 ... but it would be nice if there was some kind of syntax sugar in place
 that would avoid such a verbose solution.
 
 I know that there have been requests for runtime overflow detection that
 is on by default (bearophile?), but it could be good to have some simple
 way to indicate "really, no overflow" even where by default it's not
 provided.
 
 (Motivation: suppose that you have some kind of function that takes a
 size_t and uses that to determine an allocation.  If a negative number
 gets passed by accident, the function will thus try to allocate 2^64 - n
 elements, and your computer will have a very happy time...:-)
Just for reference: http://forum.dlang.org/thread/kn3f9v$25pd$1 digitalmars.com
Nov 10 2013
parent "rumbu" <rumbu rumbu.ro> writes:
On Monday, 11 November 2013 at 07:52:34 UTC, luka8088 wrote:

 Just for reference:
 http://forum.dlang.org/thread/kn3f9v$25pd$1 digitalmars.com
Again, this has nothing to do with runtime overflow checking. It's a compiler thing. It will be nice if the compiler will not accept implicit conversions from signed types to unsigned ones for negative values. An explicit cast can be used if someone wants to represent a negative number as unsigned. Another consequence of this behaviour is the impossibility to select automatically an overload for signed and unsigned arguments: void foo(ulong x) {} void foo(long x) {} foo(-3) //=> error, both match
Nov 11 2013