[comp.lang.c] variable limits

bill@twwells.uucp (T. William Wells) (01/30/89)

[This may be a repost. Sorry if so.]

In article <6419@polya.Stanford.EDU> crew@Polya.Stanford.EDU (Roger Crew) writes:
: Here's a quiz:
: How would you write the following in C?
:
:       VAR a, b, c : Char;
:       ...
:       FOR c = a TO b DO ... END;
:
: You can even assume that the body of the loop affects neither a nor b.
: Hint:  the answer is *not*
:
:       char a, b, c;
:       ...
:       for (c = a; c <= b; ++c) { ... }

No, you write it:

	int a, b, c;    /* or char a,b; int c; */
	...
	for (c = a; c <= b; ++c) { ... }

It is, in general, a bad practice to use a char as an iteration
control variable.

This example does, however, point up something that must be dealt
with in any language: each variable has limiting points where its
behavior becomes unreliable.  (Even languages that allow unbounded
precision have this problem, though their limits are usually
ridiculously large.) At those limits, one must take special care to
avoid passing them. For integral types in C, the limits are:

	char    0..127                          0..2**7-1
signed
	char    -127..127 (ANSI C signed char)  -2**7+1..2**7-1
	short   -32767..32767                   -2**15+1..2**15-1
	int     -32767..32767                   -2**15+1..2**15-1
	long    -2147483647..2147483647         -2**31+1..2**31-1
unsigned
	char    0..255                          0..2**8-1
	short   0..65535                        0..2**16-1
	int     0..65535                        0..2**16-1
	long    0..4294967295                   0..2**32-1

Any time your values might get even close to these limits you need to
examine the code to see if there is a possibility that something
overflows.

Of course, this problem is not restricted to integers. Floats have
this problem too, not to mention their problems with precision.
Pointers into objects also have this kind of problem.  Consider this
nonportable code:

	for (p = &array[limit]; --p >= array; ) { ... }

Since p will point before array at the last iteration, this may fail.
To give a concrete example, consider a machine with a data address
space that starts at zero (e.g., any machine with split I&D, like a
PDP-11 or an 8086), and an array whose element size is n and which is
stored at address m < n. When p decrements past the start of array,
its new value is unlikely to be m - n, a negative number.  Since the
address computation is likely to be done unsigned (as long as
sizeof(int) == sizeof(pointer), anyway), the actual value is the
unsigned version of m - n, a very large number and in any case, not
less than array. So the loop never terminates.  (Yes, Chris, I
remember!)

---
Bill
{ uunet!proxftl | novavax } !twwells!bill