From an Example
unsigned long x = 12345678UL
We have always learnt that the compiler needs to see only “long” in the above example to set 4 bytes (in 32 bit) of memory. The question is why is should we use L/UL in long constants even after declaring it to be a long.
When a suffix
LorULis not used, the compiler uses the first type that can contain the constant from a list (see details in C99 standard, clause 6.4.4:5. For a decimal constant, the list isint,long int,long long int).As a consequence, most of the times, it is not necessary to use the suffix. It does not change the meaning of the program. It does not change the meaning of your example initialization of
xfor most architectures, although it would if you had chosen a number that could not be represented as along long. See also codebauer’s answer for an example where theUpart of the suffix is necessary.There are a couple of circumstances when the programmer may want to set the type of the constant explicitly. One example is when using a variadic function:
A common reason to use a suffix is ensuring that the result of a computation doesn’t overflow. Two examples are:
In both examples, without suffixes, the constants would have type
intand the computation would be made asint. In each example this incurs a risk of overflow. Using the suffixes means that the computation will be done in a larger type instead, which has sufficient range for the result.As Lightness Races in Orbit puts it, the litteral’s suffix comes before the assignment. In the two examples above, simply declaring
xaslongandyasunsigned long longis not enough to prevent the overflow in the computation of the expressions assigned to them.Another example is the comparison
x < 12Uwhere variablexhas typeint. Without theUsuffix, the compiler types the constant12as anint, and the comparison is therefore a comparison of signed ints.With the
Usuffix, the comparison becomes a comparison of unsigned ints. “Usual arithmetic conversions” mean that -3 is converted to a large unsigned int:In fact, the type of a constant may even change the result of an arithmetic computation, again because of the way “usual arithmetic conversions” work.
Note that, for decimal constants, the list of types suggested by C99 does not contain
unsigned long long. In C90, the list ended with the largest standardized unsigned integer type at the time (which wasunsigned long). A consequence was that the meaning of some programs was changed by adding the standard typelong longto C99: the same constant that was typed asunsigned longin C90 could now be typed as a signedlong longinstead. I believe this is the reason why in C99, it was decided not to haveunsigned long longin the list of types for decimal constants.See this and this blog posts for an example.