Numeric Literals -

Numeric Literals

To read original PDF of the print article, click here.

Numeric Literals

Dan Saks

Every literal has a type.It may not be obvious, and it may vary across platforms,but the standard does specify it precisely.

The C language provides severaldifferent kinds of constants: integerconstants such as 10 and 0x1C , floatingconstants such as 1.0 and 6.022e+23 ,and character constants such as 'a' and 'x10' . C also provides string literals such as "ouch!" and "n" . C++ providesthe same kinds of constants andliterals, except the C++ standard justcalls all of them literals instead. I do,too.

Every literal in C and C++ has atype. For example, 10 is obviously aninteger. But is it an int (which issigned by default) an unsigned int , or a short or long variationthereof? Do you even care?If you're a C programmer, youmight not care. Part of me hopesyou'd care, but I'm not absolutelysure you need to. Many C programmersapparently get by quite wellwithout knowing the exact types ofconstants.

If you're a C++ programmer, youreally should care. C++ supportsfunction name overloading, and theexact type of a literal just mightdetermine which function is the bestmatch for a particular call. Forexample, given:

int f(int);
unsigned int f(unsigned int);
long int f(long int);

which of these functions does f(10) call? The answer is:

int f(int);

because the precise type of 10 is (signed)int .

Forms of integer literals
An integer literal takes differentforms:

  • A decimal integer literal (base 10) is a non-zero digit followed by zero or more decimal digits
  • A hexadecimal integer literal (base sixteen) is 0x or 0X followed by a sequence of one or more hexadecimal digits
  • An octal integer literal (base eight) is the digit 0 followed by a sequence of zero or more octal digits

For example, the decimal integer literal63 can also be expressed as the hexadecimalinteger literal 0x3F or as theoctal integer literal 077 .

Any integer literal may have a suffixthat influences its type:

U or u specifies that the literal has an unsigned typeL or l specifies that the literal has a long typeLL or ll specifies that the literal has a long long type. (This is available in the most recent edition of Standard C, C99, but not in earlier versions of C or in C++)

For example, 63u has type unsignedint . 0x3FL has type (signed)long int .An integer literal suffix may combineU with either L or LL (in either upperor lower case and in either order), sothat both 63ul and 0x3FLU have typeunsigned long int .

An integer literal's suffix influencesthe literal's type, but does not determineit. The type also depends on theliteral's value.

Types of integer literals
In general, an integer literal's type isthe smallest integer type no smallerthan int that can hold the literal'svalue and still satisfy the constraintsimposed by the form and suffix. Forexample, the type of a decimal integerliteral with no suffix is the smallest(the first) of the following types thatcan represent its value: int , long int ,and in C99, long long int . Becausethe maximum values of the types varyacross platforms, the exact types formany integer literals also vary acrossplatforms.

Both the C and C++ standards allowconsiderable slack in the range of valuesfor integer types. The maximumvalue for an int must be at least215 -1, and the maximum value for along int must be at least 231 -1. Inpractice, this means that an int mustoccupy at least 16 bits and a longint must occupy at least 32 bits.

On any platform, int and long int may occupy more than their minimumstorage requirement, as long as a long int occupies at least as much storage asan int . An unsigned integer type mustoccupy the same amount of storage as itscorresponding signed integer type. Forinstance, a 16-bit platform might use 16bits for int and unsigned int and 32bits for long int and unsigned long int . A 32-bit platform might use 32 bitsfor all four types, int , unsigned int ,long int , and unsigned long int .

Table 1 describes the rules for determiningthe type of an integer literal inC99 and C++. A literal whose value can'tbe represented in any of the listed typesproduces a compile error.

Click on image to enlarge.

The rules in Table 1 lead to somepotential portability problems. A decimalinteger literal whose value is notgreater than 32,767 (= 215 -1) has typeint on every standard C and C++ environment.No surprise there. However,any decimal integer literal whose value isgreater than 215 -1 but not greater than231 -1 has type long int on a 16-bit platform,but just plain int on a 32-bit platform.

For example, given the overloadedfunctions:

int f(int);unsigned int f(unsigned int);long int f(long int);unsigned long int	f(unsigned long int);

calling f(32768) calls f(long int) when compiled using C++ for a 16-bitplatform, but it calls f(int) when compiledfor a 32-bit platform. On the otherhand, if you write the call as f(0x8000) (0x8000 is 32,768 as a hexadecimal literal),it calls f(unsigned int) on everyplatform.

Floating literals
Floating literals offer a few little surprises,too. The type of a floating literal suchas 1.0 or 6.022e+23 is double , notfloat . Appending the letter F or f toa floating literal makes its type float .Appending the letter L or l to a floatingliteral makes its type long double . Forexample, 1.0F has type float , and6.022e+23L has type long double .Combining F and L (in either case andin either order) in a floating literal is asyntax error.

In C++, the only form of a floating literalis a decimal floating literal, in whichall of the digits (in both the significantpart and the exponent part) are decimaldigits. C99 also provides hexadecimalfloating literals, in which the digits of thesignificant part are hexadecimal digits.

In a decimal floating literal, theexponent part is optional. If present, itbegins with E or e followed by decimaldigits representing a power of 10. In ahexadecimal floating literal, the exponentpart is mandatory. Since E and e are valid hexadecimal digits, a hexadecimalfloating literal uses P or p to markthe beginning of the exponent part, followingby decimal digits representing apower of two. For example,0x1.FFFFFEp127f is a floating constantwhose value is 0x1.FFFFFE multiplied by2127 (decimal). The f at the end of theliteral specifies that the literal's type is float .

Neither the form nor value of afloating literal affects its type. The suffixletter (or absence thereof) completelydetermines the type.

Character and string literals
Integer and floating literals are essentiallythe same in both C and C++. The differenceslie in C's added support forlong long integer types and hexadecimalfloating literals. In contrast, characterand string literals behave slightly differentlybetween C and C++. Those differencesare my topic for next time.

Dan Saks is the president of Saks &Associates, a C/C++ training and consultingcompany. He is also a consulting editor for theC/C++ Users Journal. He served for manyyears as secretary of the C++ standards committee.With Thomas Plum, he wrote C++Programming Guidelines (Plum Hall).

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.