Monday, May 16, 2011

When should the const modifier be used?

There are several reasons to use const pointers. First, it allows the compiler to catch errors in which code
accidentally changes the value of a variable, as in
while (*str = 0) /* programmer meant to write *str != 0 */
{
/* some code here */
str++;
}
in which the = sign is a typographical error. Without the const in the declaration of str, the program would
compile but not run properly.
Another reason is efficiency. The compiler might be able to make certain optimizations to the code generated
if it knows that a variable will not be changed. Any function parameter which points to data that is not modified by the function or by any function it calls
should declare the pointer a pointer to const. Function parameters that are passed by value (rather than
through a pointer) can be declared const if neither the function nor any function it calls modifies the data.
In practice, however, such parameters are usually declared const only if it might be more efficient for the
compiler to access the data through a pointer than by copying it.


How reliable are floating-point comparisons? Floating-point numbers are the “black art” of computer programming. One reason why this is so is that there
is no optimal way to represent an arbitrary number. The Institute of Electrical and Electronic Engineers
(IEEE) has developed a standard for the representation of floating-point numbers, but you cannot guarantee
that every machine you use will conform to the standard.
Even if your machine does conform to the standard, there are deeper issues. It can be shown mathematically
that there are an infinite number of “real” numbers between any two numbers. For the computer to
distinguish between two numbers, the bits that represent them must differ. To represent an infinite number
of different bit patterns would take an infinite number of bits. Because the computer must represent a large
range of numbers in a small number of bits (usually 32 to 64 bits), it has to make approximate representations
of most numbers.
Because floating-point numbers are so tricky to deal with, it’s generally bad practice to compare a floatingpoint
number for equality with anything. Inequalities are much safer. If, for instance, you want to step
through a range of numbers in small increments, you might write this:
#include
const float first = 0.0;
const float last = 70.0;
const float small = 0.007;
main()
{
float f;
for (f = first; f != last && f < last + 1.0; f += small) ; printf(“f is now %g\n”, f); } However, rounding errors and small differences in the representation of the variable small might cause f to never be equal to last (it might go from being just under it to being just over it). Thus, the loop would go past the value last. The inequality f < last + 1.0 has been added to prevent the program from running on for a very long time if this happens. If you run this program and the value printed for f is 71 or more, this is what has happened. A safer way to write this loop is to use the inequality f < last to test for the loop ending, as in this example: float f; for (f = first; f < last; f += small) ; You could even precompute the number of times the loop should be executed and use an integer to count iterations of the loop, as in this example: float f; int count = (last - first) / small; for (f = first; count-- > 0; f += small)