mirror of
https://github.com/boostorg/safe_numerics.git
synced 2026-02-23 03:52:23 +00:00
a) made trap_exception work b) updated manual and examples to show how to use library to eliminate runtime penalty c) added in safe_literal d) made corrections of various types
166 lines
8.2 KiB
XML
166 lines
8.2 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE section PUBLIC "-//Boost//DTD BoostBook XML V1.1//EN"
|
|
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
|
<section id="safe_numerics.tutorial">
|
|
<title>Tutorial and Motivating Examples</title>
|
|
|
|
<section id="safe_numerics.tutorial.1">
|
|
<title>Arithmetic Expressions Can Yield Incorrect Results.</title>
|
|
|
|
<para>When some operation results in a result which exceeds the capacity
|
|
of a data variable to hold it, the result is undefined. This is called
|
|
"overflow". Since word size can differ between machines, code which
|
|
produces correct results in one set of circumstances may fail when
|
|
re-compiled on a machine with different hardware. When this occurs, Most
|
|
C++ compilers will continue to execute with no indication that the results
|
|
are wrong. It is the programmer's responsibility to ensure such undefined
|
|
behavior is avoided.</para>
|
|
|
|
<para>This program demonstrates this problem. The solution is to replace
|
|
instances of <code>char</code> type with <code>safe<char></code>
|
|
type.</para>
|
|
|
|
<programlisting><xi:include href="../../examples/example1.cpp"
|
|
parse="text" xmlns:xi="http://www.w3.org/2001/XInclude"/></programlisting>
|
|
|
|
<para>Note that I've used <code>char</code> types in this example to make
|
|
the problem and solution easier to see. The exact same example could have
|
|
been done with <code>int</code> types albeit with different values.</para>
|
|
</section>
|
|
|
|
<section id="safe_numerics.tutorial.2">
|
|
<title>Arithmetic Operations can Overflow Silently</title>
|
|
|
|
<para>A variation of the above is when a value is incremented/decremented
|
|
beyond it's domain. This is a common problem with for loops.</para>
|
|
|
|
<programlisting><xi:include href="../../examples/example2.cpp"
|
|
parse="text" xmlns:xi="http://www.w3.org/2001/XInclude"/></programlisting>
|
|
|
|
<para>When variables of unsigned integer type are decremented below zero,
|
|
they "roll over" to the highest possible unsigned version of that integer
|
|
type. This is a common problem which is generally never detected.</para>
|
|
</section>
|
|
|
|
<section id="safe_numerics.tutorial.4">
|
|
<title>Implicit Conversions Change Data Values</title>
|
|
|
|
<para>A simple assignment or arithmetic expression will convert all the
|
|
terms to the same type. Sometimes this can silently change values. For
|
|
example, when a signed data variable contains a negative type, assigning
|
|
to a unsigned type will be permitted by any C/C++ compiler but will be
|
|
treated as large unsigned value. Most modern compilers will emit a compile
|
|
time warning when this conversion is performed. The user may then decide
|
|
to change some data types or apply a <code>static_cast</code>. This is
|
|
less than satisfactory for two reasons:</para>
|
|
|
|
<para><itemizedlist>
|
|
<listitem>
|
|
<para>It may be unwieldy to change all the types to signed or
|
|
unsigned.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>We may believe that our signed type will never contain a
|
|
negative value. <code>static_cast</code> changes the data type - not
|
|
the data value. If we ignore the any compiler warnings or use a
|
|
<code>static_cast</code> to suppress them, we'll fail to detect a
|
|
program error when it is committed. This is aways a risk with
|
|
casts.</para>
|
|
</listitem>
|
|
</itemizedlist></para>
|
|
|
|
<para>This solution is simple, Just replace instances of the <code>int
|
|
</code>with <code>safe<int></code>.<programlisting><xi:include
|
|
href="../../examples/example4.cpp" parse="text"
|
|
xmlns:xi="http://www.w3.org/2001/XInclude"/></programlisting></para>
|
|
</section>
|
|
|
|
<section id="safe_numerics.tutorial.10">
|
|
<title>Mixing Data Types Can Create Subtle Errors</title>
|
|
|
|
<para>C++ contains signed and unsigned integer types. In spite of their
|
|
names, they function differently which often produces surprising results
|
|
for some operands. Program errors from this behavior can be exceedingly
|
|
difficult to find. This has lead to recommendations of various ad hoc
|
|
"rules" to avoid these problems. It's not always easy to apply these
|
|
"rules" to existing code without creating even more bugs. Here is a
|
|
typical example of this problem:</para>
|
|
|
|
<para><programlisting><xi:include href="../../examples/example10.cpp"
|
|
parse="text" xmlns:xi="http://www.w3.org/2001/XInclude"/></programlisting>Here
|
|
is the output of the above program:<programlisting>example 10: mixing types produces surprising results
|
|
Not using safe numerics
|
|
10000
|
|
4294957296
|
|
Using safe numerics
|
|
10000
|
|
detected error:converted negative value to unsigned
|
|
</programlisting>This solution is simple, Just replace instances of the
|
|
<code>int</code>with <code>safe<int></code>.</para>
|
|
</section>
|
|
|
|
<section id="safe_numerics.tutorial.5">
|
|
<title>Array Index Value Can Exceed Array Limits</title>
|
|
|
|
<para>Using an intrinsic C++ array, it's very easy to exceed array limits.
|
|
This can fail to be detected when it occurs and create bugs which are hard
|
|
to find. There are several ways to address this, but one of the simplest
|
|
would be to use safe_unsigned_range;</para>
|
|
|
|
<para><programlisting><xi:include href="../../examples/example5.cpp"
|
|
parse="text" xmlns:xi="http://www.w3.org/2001/XInclude"/></programlisting>Collections
|
|
like standard arrays, vectors do array index checking in some function
|
|
calls and not in others so this may not be the best example. However it
|
|
does illustrate the usage of <code>safe_range<T></code> for
|
|
assigning legal range to variables. This will guarantee that under no
|
|
circumstances will the variable contain a value outside of the specified
|
|
range.</para>
|
|
</section>
|
|
|
|
<section id="safe_numerics.tutorial.6">
|
|
<title>Checking of Input Values Can Be Easily Overlooked</title>
|
|
|
|
<para>It's way too easy to overlook the checking of parameters received
|
|
from outside the current program.<programlisting><xi:include
|
|
href="../../examples/example6.cpp" parse="text"
|
|
xmlns:xi="http://www.w3.org/2001/XInclude"/></programlisting>Without
|
|
safe integer, one will have to insert new code every time an integer
|
|
variable is retrieved. This is a tedious and error prone procedure. Here
|
|
we have used program input. But in fact this problem can occur with any
|
|
externally produced input.</para>
|
|
</section>
|
|
|
|
<section id="safe_numerics.tutorial.7">
|
|
<title>Programming by Contract is Too Slow</title>
|
|
|
|
<para>Programming by Contract is a highly regarded technique. There has
|
|
been much written about it has been proposed as an addition to the C++
|
|
language <citation>Garcia</citation><citation>Crowl &
|
|
Ottosen</citation>. It (mostly) depends upon runtime checking of parameter
|
|
and object values upon entry to and exit from every function. This can
|
|
slow the program down considerably which in turn undermines the main
|
|
motivation for using C++ in the first place! One popular scheme for
|
|
addressing this issue is to enable parameter checking only during
|
|
debugging and testing which defeats the guarantee of correctness which we
|
|
are seeking here! Programming by Contract will never be accepted by
|
|
programmers as long as it is associated with significant additional
|
|
runtime cost.</para>
|
|
|
|
<para>The Safe Numerics Library has facilities which, in many cases, can
|
|
check guarantee parameter requirements with little or no runtime overhead.
|
|
Consider the following example:</para>
|
|
|
|
<para><programlisting><xi:include href="../../examples/example7.cpp"
|
|
parse="text" xmlns:xi="http://www.w3.org/2001/XInclude"/></programlisting></para>
|
|
|
|
<para>In the example above the function convert incurs significant runtime
|
|
cost every time the function is called. By using "safe" types, this cost
|
|
is moved to moment when the parameters are constructed. Depending on how
|
|
the program is constructed, this may totally eliminate extraneous
|
|
computations for parameter requirement type checking. In this scenario,
|
|
there is no reason to suppress the checking for release mode and our
|
|
program can be guaranteed to be always arithmetically correct.</para>
|
|
</section>
|
|
</section>
|