10.7 Literal Constant Types and Formats

A literal constant is used to represent a numerical value in the source code; for example, 123 is a constant. Like any value, a literal constant must have a C type. In addition to a literal constant’s type, the actual value can be specified in one of several formats. The format of integral literal constants specifies their radix. MPLAB XC16 supports the ANSI standard radix specifiers as well as ones which enables binary constants to be specified in C code.

The formats used to specify the radices are given in the following table. The letters used to specify binary or hexadecimal radices are case insensitive, as are the letters used to specify the hexadecimal digits.

Table 10-4. Radix formats
Radix Format Example
binary 0b number or 0B number 0b10011010
octal 0 number 0763
decimal number 129
hexadecimal 0x number or 0X number 0x2F

Any integral literal constant will have a type of int, long int or long long int, so that the type can hold the value without overflow. Literal constants specified in octal or hexadecimal may also be assigned a type of unsigned int, unsigned long int or unsigned long long int if the signed counterparts are too small to hold the value.

The default types of literal constants may be changed by the addition of a suffix after the digits, e.g., 23U, where U is the suffix. The table below shows the possible combination of suffixes, and the types that are considered when assigning a type. So, for example, if the suffix l is specified and the value is a decimal literal constant, the compiler will assign the type long int, if that type will hold the lineal constant; otherwise, it will assign long long int. If the literal constant was specified as an octal or hexadecimal constant, then unsigned types are also considered.

Table 10-5. Suffixes and assigned types
SuffixDecimalOctal or Hexadecimal
u or Uunsigned int

unsigned long int

unsigned long long int

unsigned int

unsigned long int

unsigned long long int

l or Llong int

long long int

long int

unsigned long int

long long int

unsigned long long int

u or U, and l or Lunsigned long int

unsigned long long int

unsigned long int

unsigned long long int

ll or LLlong long intlong long int

unsigned long long int

u or U, and ll or LLunsigned long long intunsigned long long int

Here is an example of code that may fail because the default type assigned to a literal constant is not appropriate:

unsigned long int result;
unsigned char shifter;

void main(void)
{
   shifter = 20;
   result = 1 << shifter;
   // code that uses result
}

The literal constant 1 will be assigned an int type; hence the result of the shift operation will be an int and the upper bits of the long variable, result, can never be set, regardless of how much the literal constant is shifted. In this case, the value 1 shifted left 20 bits will yield the result 0, not 0x100000.

The following uses a suffix to change the type of the literal constant, hence ensure the shift result has an unsigned long type.

result = 1UL << shifter;

Floating-point literal constants have double type unless suffixed by f or F, in which case it is a float constant. The suffixes l or L specify a long double type. In MPLAB XC16, the double type equates to a 32-bit float type. The command line option, -fno-short-double, may be use to specify double as a 64-bit long double type.

Fixed-point literal constants look like floating point numbers, suffixed with combinations of [u][h,l]<r,k>. The suffix u means unsigned. The suffixes h and l signify short and long respectively. The suffix r denotes a _Fract type and k specifies an _Accum type. So for example, -1.0r is a signed _Fract and 0.5uhk is an unsigned short _Accum.

Character literal constants are enclosed by single quote characters, , for example ‘a’. A character literal constant has int type, although this may be optimized to a char type later in the compilation.

Multi-byte character literal constants are supported by this implementation.

String constants, or string literals, are enclosed by double quote characters ", for example "hello world". The type of string literal constants is const char * and the character that make up the string may be stored in the program memory.

To comply with the ANSI C standard, the compiler does not support the extended character set in characters or character arrays. Instead, they need to be escaped using the backslash character, as in the following example:

const char name[] = "Bj\xf8k";

printf("%s's Resum\xe9", name); \\ prints "Bjørk's Resumé"

Defining and initializing a non-const array (i.e., not a pointer definition) with a string, for example:

char ca[]= "two"; // "two" different to the above

is a special case and produces an array in data space which is initialized at startup with the string "two", whereas a string literal constant used in other contexts represents an unnamed array, accessed directly from its storage location.

The compiler will use the same storage location and label for strings that have identical character sequences, except where the strings are used to initialize an array residing in the data space as shown in the last statement in the previous example.

Two adjacent string literal constants (i.e., two strings separated only by white space) are concatenated by the C preprocessor. Thus:

const char * cp = "hello " "world"; will assign the pointer with the address of the string "hello world."