# The Case Against int, Part 2: Why Signed Integers?

Last week, I argued that the `int`

type was often dangerous because its capacity depends on the implementation. In addition to its implementation-defined precision, `int`

has another drawback, namely that it is signed. As it turns out, unsigned integer arithmetic is often more useful than signed.

For example, a common use of integers is to count things: the number of students in a course, cars in a parking lot, records in a file, and so on. In general, counters cannot be negative; so unsigned types are often more appropriate than signed integer types such as `int`

. Moreover, one common use of such integers is as array or container indices or sizes. For built-in data structures, C++ provides the unsigned type `size_t`

and the corresponding signed type `ptrdiff_t`

; moreover, each library container type has its own `size_type`

that has room for the number of elements in the largest container of each type. So for counting things that can fit in memory, you are probably better off using `size_t`

or *container*`::size_type`

than you are in using `int`

, or even `unsigned`

. For counting items in files, `unsigned long`

is probably right.

Integers are also commonly used to deal with external quantities. These can be imported from elsewhere, such as numbers that appear in data files, or they can represent things in the physical world that naturally come in integer form, such as dates. In such cases, it is often possible to put bounds on the values that these quantities can have.

If you know these bounds, you know whether a signed or unsigned type is appropriate to deal with them. What you don't know is which specific. One reader noted that C++ has types such as `int32_t`

, which let you specify a specific number of bits in an integer. However, this specification isn't as useful as it looks at first.

For example, suppose we want to be able to deal with signed integers up to 1000000. If we happen to be running on a machine with 24-bit integers, we can fit such an integer in an `int`

. In fact, we can do so even if `int`

is 21 bits, including sign; but there's no `int21_t`

type available for the purpose.

What *is* available is code like this:

typedef decltype(1000000) million_int;

This code takes advantage of the `decltype`

feature of C++11 to determine the type of the literal `1000000`

. That type, in turn, is defined to be the first of `int`

, `long`

, and `long long`

that has enough room to contain this particular value on this implementation. It is then possible to use `million_int`

wherever a signed integer type is needed that has room for `1000000`

.

We can now list our recommendations:

- If you are counting array elements, use
`size_t`

, or its corresponding signed type`ptrdiff_t`

. - If you are counting container elements, use container::
`size_type`

or the corresponding signed type container::`difference_type`

. - If you are counting data in a file, use
`unsigned long`

. - If you want to work with integers within a known range, use
`decltype`

on a literal to determine the corresponding type.

So far, I haven't come up with a similarly succinct recommendation for when to use `int`

.

Next week, we'll look at some of the hazards of combining signed and unsigned numbers.