C supports the data types available in most CPUs, as well as some extended types. Table 17.1, “C Data Types” outlines the standard data types available in C.
Table 17.1. C Data Types
C Type | Description | Range | Precision |
---|---|---|---|
char | 8-bit signed integer | -128 to +127 | Exact |
short | 16-bit signed integer | -32,768 to +32,767 | Exact |
int | 16 or 32-bit signed integer (usually 16 bits on 8 or 16-bit processors, 32-bits on 32 or 64-bit processors) | -32,768 to +32,767 or -2,147,483,648 to +2,147,483,647 | Exact |
long | 32 or 64-bit signed integer (usually 32 bits on 16-bit and 32-bit processors, 64 bits on 64-bit processors) | -2,147,483,648 to +2,147,483,647 or +/- 9.22337203685e+18 | Exact |
long long | 64 or 128-bit signed integer | +/- 9.22337203685e+18 or +/- 1.7014118346e+38 | Exact |
unsigned char | 8-bit unsigned integer | 0 to 255 | Exact |
unsigned short | 16-bit unsigned integer | 0 to 65,535 | Exact |
unsigned int | 16 or 32-bit unsigned integer | 0 to 65,535 or 4,294,967,295 | Exact |
unsigned long | 32 or 64-bit unsigned integer | 0 to 4,294,967,295 or 1.84467440737e+19 | Exact |
unsigned long long | 64 or 128-bit unsigned integer | 0 to 1.84467440737e+19 or 3.40282366921e+38 | Exact |
float | Almost always 32-bit floating point | +/- (1.1754 x 10-38 to 3.4028 x 1038) | 24 bits (6-7 decimal digits) |
double | Almost always 64-bit floating point | +/- (2.2250 x 10-308 to 1.7976 x 10308) | 52 bits (15-16 decimal digits) |
long double | 64, 80, 96, or 128-bit floating point | +/- 3.3621 x 10-4932 to 1.1897 x 10+4932) | 114 bits (64 decimal digits) |
float complex | Two floats for real and imaginary parts | Same as float | Same as float |
double complex | Two doubles for real and imaginary parts | Same as double | Same as double |
long double complex | Two 128-bit floating point values | Same as long double | Same as long double |
C's int
, long
, and long long
types vary in size from one platform to
another. Because of this, we have to make pessimistic assumptions
about the range of these types in order to write portable code.
We must assume that an int
has the range of a 16-bit
integer and the memory requirements of a 32-bit integer, because
it will on some systems. NEVER ASSUME THAT YOUR CODE WILL ONLY BE
USED ON THE CPU AND OPERATING SYSTEM WHERE YOU WROTE IT.
Likewise, we have to assume a long
has the range of
a 32-bit integer and the memory requirements of a 64-bit integer.
On 16-bit processors, int
is typically
16 bits, while long
is 32 bits, requiring multiple
precision arithmetic. On 32-bit machines, both int
and long
are typically 32 bits. On 64-bit machines,
int
is usually 32 bits while long
is
usually 64 bits.
To summarize, an int
could be either 16 or 32 bits,
depending on where your code is compiled. A long
could be wither 32 or 64 bits, depending where your code is
compiled. Use int
or long
only if
either possible size is acceptable in terms of range and memory use.
The size of int
and long
vary across
CPUs for the sake of speed. The int
type never requires
multiple precision arithmetic, except perhaps on very small
8-bit microcontrollers, where an int
may be 16 bits. Hence, if you want to maximize speed, and 16 bits
provides enough range, and 32 bits isn't too much memory to use,
then use int
. Likewise, if 32 bits provides enough
range, and 64 bits isn't too much memory to use, then use long.
If you need signed integers larger than +32,767 or an unsigned
integer larger than 65,535, then int
or
unsigned int
will not be big enough on 16-bit systems.
Use at
least a long
. Always consider using unsigned
before going to a larger data type. If you need values up to 50,000,
but do not need negative values, then unsigned int
will suffice and you do not need long
, which
uses more memory and may require multiple machine instructions to
process.
If you want to ensure a specific size for an integer variable
regardless of whether it means using multiple precision arithmetic,
there are additional types defined in inttypes.h
,
such as int64_t
and uint64_t
.
#include <inttypes.h> int main(int argc, char*argv[]) { int32_t myint; ... return 0; }
If you don't need numbers larger than +32,767 and you want to
limit the size of the variable to 2 bytes, then use
short
. This is typically only done on embedded
systems with very little memory or when using very large arrays
on a typical computer. Note that short values will be
promoted to int
in many situations, which
will slow down the program.
Logical/Boolean values in C do not have a separate data type. Instead,
C treats them as they are handled internally, as integers. A value of
0 represents false, and any non-zero value represents true.
The standard header file stdbool.h
defines a data type
called bool
and constants true
and
false
. You can use these instead of integer
variables and values to make programs that
use Boolean variables more self-documenting.
For real numbers, use double
unless saving memory
is an issue. There is no significant difference in speed between
float
and double
on modern CPUs,
and double
has much higher precision. Only use
float
for very large arrays to reduce memory use.
Why do the size of int
and long
types
vary from one computer to another?
What would be the best C data type to use for each of the following values? Explain your reasoning in each case. Use the C types table in the text and the adjoining explanations to make optimal choices.
A single variable containing a person's age, in years.
A single variable holding the temperature of a star, up to 40,000 Kelvin. The value is only approximate within 1,000 degrees.
A huge array of people's ages in years.
The balance of Joe Sixpack's checking account, in pennies.
A single variable holding Avogadro's constant.
A large array holding values like Avogadro's constant.