整理自 C++ Primer, 5th Edition
Some languages, such as Smalltalk and Python, check types at run time. In contrast, C++ is a statically typed language; type checking is done at compile time. As a consequence, the compiler must know the type of every name used in the program.
C++ allows programmers to define types that include operations as well as data. A major design goal of C++ is to let programmers define their own types that are as easy to use as the built-in types.
C++ primitive types that include:
- the arithmetic types
- a special type
|wchar_t||wide character||16 bits|
|char16_t||Unicode character||16 bits|
|char32_t||Unicode character||32 bits|
|short||short integer||16 bits|
|long||long integer||32 bits|
|long long||long integer||64 bits|
|float||single-precision floating-point||6 significant digits|
|double||double-precision floating-point||10 significant digits|
|long double||extended-precision floating-point||10 significant digits|
The size of—that is, the number of bits in—the arithmetic types varies across machines. The standard guarantees minimum sizes as listed in Table 2.1. However, compilers are allowed to use larger sizes for these types. Because the number of bits varies, the largest (or smallest) value that a type can represent also varies. 比如 int 在 32-bit 系统的 Visual Studio 2008 下就是 32 bits 长的。规范只规定了诸如 “int: Not smaller than short. At least 16 bits.” 这样的大规范，不同的机器、不同的编译器可以有不同的 type size。（源出：Variables and types）
__int32 一定是 32 bits，具体见 Data Type Ranges 和 What does the C++ standard state the size of int, long type to be?。
char is guaranteed to be big enough to hold numeric values corresponding to the characters in the machine’s basic character set. That is, a
char is the same size as a single machine byte.
The smallest chunk of addressable memory is referred to as a “byte.” The basic unit of storage, usually a small number of bytes, is referred to as a “word.” On most machines a byte contains 8 bits and a word is either 32 or 64 bits, that is, 4 or 8 bytes.
signed type represents negative or positive numbers (including zero); an
unsigned type represents only values >= zero.
Unlike the other integer types, there are three distinct basic character types:
(plain) char == signed char，因为有的系统是
(plain) char == signed char，有的系统是
(plain) char == unsigned char，这也是由编译器说了算的。
The standard does not define how signed types are represented, but does specify that the range should be evenly divided between positive and negative values. Hence, an 8-bit
signed char is guaranteed to be able to hold values from –127 through 127; most modern machines use representations that allow values from –128 through 127.
The remaining integral types represent integer values of (potentially) different sizes. The language guarantees that an
int will be at least as large as
long at least as large as an
long long at least as large as
long. The type
long long was introduced by the new standard.
floats are represented in one word (32 bits),
doubles in two words (64 bits), and
long doubles in either three or four words (96 or 128 bits). The type
long double is often used as a way to accommodate special-purpose floating-point hardware; its precision is more likely to vary from one implementation to another.
Advice: Deciding which Type to UseC++, like C, is designed to let programs get close to the hardware when necessary.
The arithmetic types are defined to cater to the peculiarities of various kinds of hardware. Accordingly, the number of arithmetic types in C++ can be bewildering. Most programmers can (and should) ignore these complexities by restricting the types they use. A few rules of thumb can be useful in deciding which type to use:
- Use an unsigned type when you know that the values cannot be negative.
intfor integer arithmetic.
shortis usually too small and, in practice,
longoften has the same size as
int. If your data values are larger than the minimum guaranteed size of an
int, then use
- Do not use plain
boolin arithmetic expressions. Use them only to hold characters or truth values. Computations using
charare especially problematic because
signedon some machines and
unsignedon others. If you need a tiny integer, explicitly specify either
doublefor floating-point computations;
floatusually does not have enough precision, and the cost of double-precision calculations versus single-precision is negligible. In fact, on some machines, double-precision operations are faster than single. The precision offered by
long doubleusually is unnecessary and often entails considerable run-time cost.
bool b = 42; // b is true int i = b; // i has value 1 i = 3.14; // i has value 3 double pi = i; // pi has value 3.0 unsigned char c = -1; // assuming 8-bit chars, c has value 255 signed char c2 = 256; // assuming 8-bit chars, the value of c2 is undefined int i = 42; if (i) // condition will evaluate as true i = 0;
- When we assign one of the non-
boolarithmetic types to a
boolobject, the result is false if the value is 0 and true otherwise.
- When we assign a
boolto one of the other arithmetic types, the resulting value is 1 if the bool is true and 0 if the bool is false.
- When we assign a floating-point value to an object of integral type, the value is truncated. The value that is stored is the part before the decimal point.
- When we assign an integral value to an object of floating-point type, the fractional part is zero. Precision may be lost if the integer has more bits than the floating-point object can accommodate.
- If we assign an out-of-range value to an object of
unsignedtype, the result is the remainder of the value modulo the number of values the target type can hold. For example, an 8-bit
unsigned charcan hold values from 0 through 255, inclusive. If we assign a value outside this range, the compiler assigns the remainder of that value modulo 256. Therefore, assigning –1 to an 8-bit
unsigned chargives that object the value 255.
- If we assign an out-of-range value to an object of signed type, the result is undefined. The program might appear to work, it might crash, or it might produce garbage values.
Advice: Avoid Undefined and Implementation-Defined Behavior
Undefined behavior results from errors that the compiler is not required (and sometimes is not able) to detect. Even if the code compiles, a program that executes an undefined expression is in error.
Unfortunately, programs that contain undefined behavior can appear to execute correctly in some circumstances and/or on some compilers. There is no guarantee that the same program, compiled under a different compiler or even a subsequent release of the same compiler, will continue to run correctly. Nor is there any guarantee that what works with one set of inputs will work with another.
Similarly, programs usually should avoid implementation-defined behavior, such as assuming that the size of an
int is a fixed and known value. Such programs are said to be nonportable. When the program is moved to another machine, code that relied on implementation-defined behavior may fail. Tracking down these sorts of problems in previously working programs is, mildly put, unpleasant.
Caution: Don’t Mix Signed and Unsigned Types
If we use both
int values in an arithmetic expression, the
int value ordinarily is converted to
unsigned u = 10; int i = -42; std::cout << i + i << std::endl; // prints -84 std::cout << u + i << std::endl; // if 32-bit ints, prints 4294967264 unsigned u1 = 42, u2 = 10; std::cout << u1 - u2 << std::endl; // ok: result is 32 std::cout << u2 - u1 << std::endl; // ok: but the result will wrap around // WRONG: u can never be less than 0; the condition will always succeed for (unsigned u = 10; u >= 0; --u) std::cout << u << std::endl;
Expressions that mix signed and unsigned values can yield surprising results when the signed value is negative. It is essential to remember that signed values are automatically converted to unsigned. For example, in an expression like
a * b, if
a is -1 and
b is 1, then if both
ints, the value is, as expected -1. However, if
b is an
unsigned, then the value of this expression depends on how many bits an int has on the particular machine. On our machine, this expression yields 4294967295.