A 16-bit unsigned value
Suppose an unsigned type has precision p = 16. The value 240 has bits 4, 5, 6, and 7 set. Shifting it left by 2 gives 960, with bits 6 through 9 set. Shifting it left by 9 would move one bit to position 16, which does not fit; the resulting unsigned value is 57344. Precision determines which bit positions exist. section 5.7.1 section 5.7.3
Precision is a property of a C type, not a promise about the accuracy of a calculation. It helps determine the type’s valid range. The C standard constrains the precision of basic types rather than prescribing one precision for every implementation. Distinct types can even have the same precision. section 5.2
Its consequences depend on the kind of number:
- For an unsigned integer, precision p is the number of binary digits in its representation. Its values run from 0 through 2^p − 1. Limits such as UINT_MAX, ULONG_MAX, and ULLONG_MAX expose the corresponding maximum values. section 5.7.1
- For a left shift, bits moved beyond the available positions are omitted, and the right operand must be less than the precision. Bitwise complement also depends on precision: it acts on the type’s full set of bit positions. section 5.7.3 section 5.7.2
- For floating-point data, precision p counts bits in the mantissa. Together with the exponent bounds, it describes which values the type can represent. Intermediate computations can cut off digits, so familiar algebraic rearrangements need care. section 5.7.7
TAKEAWAY: Ask what precision means for the type at hand. For a typical double, DBL_MANT_DIG reports a mantissa precision of 53 bits; it does not say that every floating-point calculation is accurate to 53 bits. The “precision” field in a printf format is a separate formatting control, not a change to the argument’s type. section 5.7.7 section 8.3.4
Table 5.4. Bounds for scalar types used in this book (view table figure)
| Name |
[min, max] |
Where |
Typical |
|---|---|---|---|
| size_t | [0, SIZE_MAX] | <stdint.h> | [0, 2w –1], w = 32, 64 |
| double | [±DBL_MIN, ±DBL_MAX] | <float.h> | [±2–w–2,±2w], w = 1024 |
| signed | [INT_MIN, INT_MAX] | <limits.h> | [–2w, 2w –1], w = 31 |
| unsigned | [0, UINT_MAX] | <limits.h> | [0, 2w –1], w = 32 |
| bool | [false, true] | <stdbool.h> | [0, 1] |
| ptrdiff_t | [PTRDIFF_MIN, PTRDIFF_MAX] | <stdint.h> | [–2w, 2w –1], w = 31, 63 |
| char | [CHAR_MIN, CHAR_MAX] | <limits.h> | [0, 2w –1], w = 7, 8 |
| unsigned char | [0, UCHAR_MAX ] | <limits.h> | [0, 255] |
Compare the listed scalar bounds and the header macros that expose them; typical bounds are examples, not universal type precisions. section 5.7.1








